1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : ** File: plgetopt.c
40 : ** Description: utilities to parse argc/argv
41 : */
42 :
43 : #include "prmem.h"
44 : #include "prlog.h"
45 : #include "prerror.h"
46 : #include "plstr.h"
47 : #include "plgetopt.h"
48 :
49 : #include <string.h>
50 :
51 : static char static_Nul = 0;
52 :
53 : struct PLOptionInternal
54 : {
55 : const char *options; /* client options list specification */
56 : PRIntn argc; /* original number of arguments */
57 : char **argv; /* vector of pointers to arguments */
58 : PRIntn xargc; /* which one we're processing now */
59 : const char *xargv; /* where within *argv[xargc] */
60 : PRIntn minus; /* do we already have the '-'? */
61 : const PLLongOpt *longOpts; /* Caller's array */
62 : PRBool endOfOpts; /* have reached a "--" argument */
63 : PRIntn optionsLen; /* is strlen(options) */
64 : };
65 :
66 : /*
67 : ** Create the state in which to parse the tokens.
68 : **
69 : ** argc the sum of the number of options and their values
70 : ** argv the options and their values
71 : ** options vector of single character options w/ | w/o ':
72 : */
73 0 : PR_IMPLEMENT(PLOptState*) PL_CreateOptState(
74 : PRIntn argc, char **argv, const char *options)
75 : {
76 0 : return PL_CreateLongOptState( argc, argv, options, NULL);
77 : } /* PL_CreateOptState */
78 :
79 140 : PR_IMPLEMENT(PLOptState*) PL_CreateLongOptState(
80 : PRIntn argc, char **argv, const char *options,
81 : const PLLongOpt *longOpts)
82 : {
83 140 : PLOptState *opt = NULL;
84 : PLOptionInternal *internal;
85 :
86 140 : if (NULL == options)
87 : {
88 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
89 0 : return opt;
90 : }
91 :
92 140 : opt = PR_NEWZAP(PLOptState);
93 140 : if (NULL == opt)
94 : {
95 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
96 0 : return opt;
97 : }
98 :
99 140 : internal = PR_NEW(PLOptionInternal);
100 140 : if (NULL == internal)
101 : {
102 0 : PR_DELETE(opt);
103 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
104 0 : return NULL;
105 : }
106 :
107 140 : opt->option = 0;
108 140 : opt->value = NULL;
109 140 : opt->internal = internal;
110 140 : opt->longOption = 0;
111 140 : opt->longOptIndex = -1;
112 :
113 140 : internal->argc = argc;
114 140 : internal->argv = argv;
115 140 : internal->xargc = 0;
116 140 : internal->xargv = &static_Nul;
117 140 : internal->minus = 0;
118 140 : internal->options = options;
119 140 : internal->longOpts = longOpts;
120 140 : internal->endOfOpts = PR_FALSE;
121 140 : internal->optionsLen = PL_strlen(options);
122 :
123 140 : return opt;
124 : } /* PL_CreateLongOptState */
125 :
126 : /*
127 : ** Destroy object created by CreateOptState()
128 : */
129 140 : PR_IMPLEMENT(void) PL_DestroyOptState(PLOptState *opt)
130 : {
131 140 : PR_DELETE(opt->internal);
132 140 : PR_DELETE(opt);
133 140 : } /* PL_DestroyOptState */
134 :
135 860 : PR_IMPLEMENT(PLOptStatus) PL_GetNextOpt(PLOptState *opt)
136 : {
137 860 : PLOptionInternal *internal = opt->internal;
138 :
139 860 : opt->longOption = 0;
140 860 : opt->longOptIndex = -1;
141 : /*
142 : ** If the current xarg points to nul, advance to the next
143 : ** element of the argv vector. If the vector index is equal
144 : ** to argc, we're out of arguments, so return an EOL.
145 : ** Note whether the first character of the new argument is
146 : ** a '-' and skip by it if it is.
147 : */
148 2440 : while (0 == *internal->xargv)
149 : {
150 860 : internal->xargc += 1;
151 860 : if (internal->xargc >= internal->argc)
152 : {
153 140 : opt->option = 0;
154 140 : opt->value = NULL;
155 140 : return PL_OPT_EOL;
156 : }
157 720 : internal->xargv = internal->argv[internal->xargc];
158 720 : internal->minus = 0;
159 720 : if (!internal->endOfOpts && ('-' == *internal->xargv))
160 : {
161 720 : internal->minus++;
162 720 : internal->xargv++; /* and consume */
163 720 : if ('-' == *internal->xargv && internal->longOpts)
164 : {
165 0 : internal->minus++;
166 0 : internal->xargv++;
167 0 : if (0 == *internal->xargv)
168 : {
169 0 : internal->endOfOpts = PR_TRUE;
170 : }
171 : }
172 : }
173 : }
174 :
175 : /*
176 : ** If we already have a '-' or '--' in hand, xargv points to the next
177 : ** option. See if we can find a match in the list of possible
178 : ** options supplied.
179 : */
180 720 : if (internal->minus == 2)
181 : {
182 0 : char * foundEqual = strchr(internal->xargv,'=');
183 0 : PRIntn optNameLen = foundEqual ? (foundEqual - internal->xargv) :
184 0 : strlen(internal->xargv);
185 0 : const PLLongOpt *longOpt = internal->longOpts;
186 0 : PLOptStatus result = PL_OPT_BAD;
187 :
188 0 : opt->option = 0;
189 0 : opt->value = NULL;
190 :
191 0 : for (; longOpt->longOptName; ++longOpt)
192 : {
193 0 : if (strncmp(longOpt->longOptName, internal->xargv, optNameLen))
194 0 : continue; /* not a possible match */
195 0 : if (strlen(longOpt->longOptName) != optNameLen)
196 0 : continue; /* not a match */
197 : /* option name match */
198 0 : opt->longOptIndex = longOpt - internal->longOpts;
199 0 : opt->longOption = longOpt->longOption;
200 : /* value is part of the current argv[] element if = was found */
201 : /* note: this sets value even for long options that do not
202 : * require option if specified as --long=value */
203 0 : if (foundEqual)
204 : {
205 0 : opt->value = foundEqual + 1;
206 : }
207 0 : else if (longOpt->valueRequired)
208 : {
209 : /* value is the next argv[] element, if any */
210 0 : if (internal->xargc + 1 < internal->argc)
211 : {
212 0 : opt->value = internal->argv[++(internal->xargc)];
213 : }
214 : /* missing value */
215 : else
216 : {
217 0 : break; /* return PL_OPT_BAD */
218 : }
219 : }
220 0 : result = PL_OPT_OK;
221 0 : break;
222 : }
223 0 : internal->xargv = &static_Nul; /* consume this */
224 0 : return result;
225 : }
226 720 : if (internal->minus)
227 : {
228 : PRIntn cop;
229 720 : PRIntn eoo = internal->optionsLen;
230 27480 : for (cop = 0; cop < eoo; ++cop)
231 : {
232 27480 : if (internal->options[cop] == *internal->xargv)
233 : {
234 720 : opt->option = *internal->xargv++;
235 720 : opt->longOption = opt->option & 0xff;
236 : /*
237 : ** if options indicates that there's an associated
238 : ** value, it must be provided, either as part of this
239 : ** argv[] element or as the next one
240 : */
241 720 : if (':' == internal->options[cop + 1])
242 : {
243 : /* value is part of the current argv[] element */
244 600 : if (0 != *internal->xargv)
245 : {
246 0 : opt->value = internal->xargv;
247 : }
248 : /* value is the next argv[] element, if any */
249 600 : else if (internal->xargc + 1 < internal->argc)
250 : {
251 600 : opt->value = internal->argv[++(internal->xargc)];
252 : }
253 : /* missing value */
254 : else
255 : {
256 0 : return PL_OPT_BAD;
257 : }
258 :
259 600 : internal->xargv = &static_Nul;
260 600 : internal->minus = 0;
261 : }
262 : else
263 120 : opt->value = NULL;
264 720 : return PL_OPT_OK;
265 : }
266 : }
267 0 : internal->xargv += 1; /* consume that option */
268 0 : return PL_OPT_BAD;
269 : }
270 :
271 : /*
272 : ** No '-', so it must be a standalone value. The option is nul.
273 : */
274 0 : opt->value = internal->argv[internal->xargc];
275 0 : internal->xargv = &static_Nul;
276 0 : opt->option = 0;
277 0 : return PL_OPT_OK;
278 : } /* PL_GetNextOpt */
279 :
280 : /* plgetopt.c */
|