1 /* LIBDGL -- a Directed Graph Library implementation
2 * Copyright (C) 2002 Roberto Micarelli
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /* best view tabstop=4
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "opt.h"
27
_ParseLongOption(GnoOption_s * pOpt,char * pszArg)28 static int _ParseLongOption(GnoOption_s * pOpt, char *pszArg)
29 {
30 char *pszLong;
31 char *pszPar;
32 char *pszMatch = NULL;
33 int nret;
34
35
36 if (pOpt->pszLong == NULL) {
37 return 0;
38 }
39
40 pszLong = strdup(pOpt->pszLong);
41
42 if ((pszPar = strchr(pszArg, '=')) != NULL) {
43 *pszPar = 0;
44 }
45 pszMatch = strdup(pszArg);
46 if (pszPar)
47 *pszPar++ = '=';
48
49 if (strcmp(pszLong, pszMatch + 2) == 0) {
50
51 /* * mandatory parameter not found
52 * */
53 if (pszPar == NULL) {
54 nret = -1;
55 goto free_and_exit;
56 }
57
58 if (pOpt->ppszValue) {
59 if (pOpt->ppszValue[0])
60 free(pOpt->ppszValue[0]);
61 pOpt->ppszValue[0] = strdup(pszPar);
62 }
63
64 nret = 1;
65 goto free_and_exit;
66 }
67
68 nret = 0;
69
70 free_and_exit:
71
72 free(pszLong);
73 free(pszMatch);
74
75 return nret;
76 }
77
_ParseLongSwitch(GnoOption_s * pOpt,char * pszArg)78 static int _ParseLongSwitch(GnoOption_s * pOpt, char *pszArg)
79 {
80
81 if (pOpt->pszLong == NULL) {
82 return 0;
83 }
84
85 if (strcmp(pOpt->pszLong, pszArg + 2) == 0) {
86 if (pOpt->pfValue)
87 *pOpt->pfValue = True;
88
89 return 1;
90 }
91
92 return 0;
93 }
94
95
_ParseShortOption(GnoOption_s * pOpt,char * pszArg,char * pszPar)96 static int _ParseShortOption(GnoOption_s * pOpt, char *pszArg, char *pszPar)
97 {
98 char *pszShort;
99 int ich;
100
101 if (pOpt->pszShort == NULL)
102 return 0;
103
104 pszShort = strdup(pOpt->pszShort);
105
106 for (ich = 1; pszArg[ich]; ich++) {
107 if (pszShort[0] == pszArg[ich]) {
108 if (pszPar == NULL || pszPar[0] == 0) {
109 free(pszShort);
110
111 return -1;
112 }
113
114 if (pszPar[0] == '-' && pszPar[1] != 0) {
115 free(pszShort);
116
117 return -1;
118 }
119
120 if (pOpt->ppszValue) {
121 if (pOpt->ppszValue[0])
122 free(pOpt->ppszValue[0]);
123 pOpt->ppszValue[0] = strdup(pszPar);
124 }
125
126 free(pszShort);
127
128 return 2;
129 }
130 }
131
132 free(pszShort);
133
134 return 0;
135 }
136
_ParseShortSwitch(GnoOption_s * pOpt,char * pszArg)137 static int _ParseShortSwitch(GnoOption_s * pOpt, char *pszArg)
138 {
139 int ich;
140
141 if (pOpt->pszShort == NULL)
142 return 0;
143
144 for (ich = 1; pszArg[ich]; ich++) {
145 if (pOpt->pszShort[0] == pszArg[ich]) {
146 if (pOpt->pfValue)
147 *pOpt->pfValue = True;
148
149 return 1;
150 }
151 }
152
153 return 0;
154 }
155
156 /***********************************************************************
157 * CALLBACKS
158 **********************************************************************/
159
160 /***********************************************************************
161 * PUBLIC FUNCTIONS
162 **********************************************************************/
163
164 /*@*--------------------------------------------------------------------
165 * @func: GnoParse()
166 * @descr: Parse argc, argv against the option array and setup option
167 * values in the array.
168 *
169 * @args: I: argc = count of argv entries
170 * I: argv -> array of pointer to string
171 * I: pOpt -> option array pointer
172 *
173 * @ret: The number of 'orphan' entries found in the argv.
174 * @see: GnoOption_s
175 *
176 * @notes: The argv array will be modified: each argv entry that contains a
177 * recognized option ( '-.' or '--...' ) or each entry recognized as
178 * a parametric option parameter, will be set to NULL.
179 * Thus, at the function return the argv entries not set to NULL are
180 * those of orphan entries (those not related to any option).
181 * The user can then scan argv to find out orphans.
182 * However the number of argv entries will not be altered.
183 *
184 *--------------------------------------------------------------------*/
185
GnoParse(int argc,char ** argv,GnoOption_s * pOpt)186 int GnoParse(int argc, char **argv, GnoOption_s * pOpt)
187 {
188 char *pszArgv;
189 char *pszArgvNxt;
190 int iArg, iOpt, cOrphan = 0;
191 int nret, cret;
192 Boolean fParseError = False;
193
194 /* * this first loop setup default values
195 * * strdup is used for non-switch options
196 * * to make life easier when freeing the field
197 * */
198 for (iOpt = 0; pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
199 if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
200 if (pOpt[iOpt].pfValue) {
201 pOpt[iOpt].pfValue[0] = pOpt[iOpt].fDef;
202 }
203 }
204 else {
205 if (pOpt[iOpt].pszDef) {
206 if (pOpt[iOpt].ppszValue) {
207 pOpt[iOpt].ppszValue[0] = strdup(pOpt[iOpt].pszDef);
208 }
209 }
210 else {
211 if (pOpt[iOpt].ppszValue) {
212 pOpt[iOpt].ppszValue[0] = NULL;
213 }
214 }
215 }
216 }
217
218 /* * for each arg in argv lookup the matching options
219 * */
220 for (iArg = 0, pszArgv = NULL;
221 iArg < argc && (pszArgv = strdup(argv[iArg])) != NULL;
222 iArg++, free(pszArgv), pszArgv = NULL) {
223
224 if (pszArgv[0] == '-' && pszArgv[1] == '-' && pszArgv[2]) { /* long style */
225 for (iOpt = 0;
226 (pOpt[iOpt].pszShort || pOpt[iOpt].pszLong) && argv[iArg];
227 iOpt++) {
228 if (pOpt[iOpt].pszLong) {
229 if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
230 nret = _ParseLongSwitch(&pOpt[iOpt], pszArgv);
231 }
232 else {
233 nret = _ParseLongOption(&pOpt[iOpt], pszArgv);
234 }
235
236 if (nret < 0) {
237 fprintf(stderr,
238 "parse option: syntax error at <%s>\n",
239 pszArgv);
240 fParseError = True;
241 }
242
243 if (nret == 1) {
244 argv[iArg] = NULL;
245 }
246 }
247 }
248
249 if (argv[iArg]) {
250 fprintf(stderr, "parse option: <%s> is out of scope\n",
251 pszArgv);
252 fParseError = True;
253 }
254 }
255 else if (argv[iArg][0] == '-' && argv[iArg][1]) { /* short style */
256 if (iArg + 1 < argc) {
257 pszArgvNxt = strdup(argv[iArg + 1]);
258 }
259 else {
260 pszArgvNxt = NULL;
261 }
262
263 for (cret = iOpt = 0;
264 pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
265 if (pOpt[iOpt].pszShort) {
266 if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
267 nret = _ParseShortSwitch(&pOpt[iOpt], pszArgv);
268 }
269 else {
270 nret =
271 _ParseShortOption(&pOpt[iOpt], pszArgv,
272 pszArgvNxt);
273 }
274 if (nret < 0) {
275 fprintf(stderr,
276 "parse option: syntax error at <%s>\n",
277 pszArgv);
278 fParseError = True;
279 }
280 else {
281 cret = (nret > cret) ? nret : cret;
282 }
283 }
284 }
285
286 if (pszArgvNxt) {
287 free(pszArgvNxt);
288 }
289
290 if (cret == 1) {
291 argv[iArg] = NULL;
292 }
293 else if (cret == 2) {
294 argv[iArg++] = NULL;
295 argv[iArg] = NULL;
296 }
297
298 }
299 else {
300 cOrphan++;
301 }
302 }
303
304 if (pszArgv)
305 free(pszArgv);
306
307 return (fParseError == True) ? -1 : cOrphan;
308 }
309
310
311 /*@*--------------------------------------------------------------------
312 * @func: GnoFree()
313 * @descr: Free resource previously created with a call to GnoParse()
314 *
315 * @args: I: pOpt -> option array pointer
316 *
317 * @see: GnoOption_s, GnoParse()
318 *
319 *--------------------------------------------------------------------*/
GnoFree(GnoOption_s * pOpt)320 void GnoFree(GnoOption_s * pOpt)
321 {
322 int iOpt;
323
324 for (iOpt = 0; pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
325 if (pOpt[iOpt].ppszValue) {
326 if (pOpt[iOpt].ppszValue[0]) {
327 free(pOpt[iOpt].ppszValue[0]);
328 pOpt[iOpt].ppszValue[0] = NULL;
329 }
330 }
331 }
332
333 }
334
335 /*@*--------------------------------------------------------------------
336 * @func: GnoHelp()
337 * @descr: Print a brief option's help on the standard error
338 *
339 * @args: I: pszHead -> help header string
340 *
341 * @args: I: pOpt -> option array pointer
342 *
343 * @see: GnoOption_s
344 *
345 *--------------------------------------------------------------------*/
GnoHelp(char * pszHead,GnoOption_s * pOpt)346 void GnoHelp(char *pszHead, GnoOption_s * pOpt)
347 {
348 int iOpt;
349
350 fprintf(stderr, "%s\n", (pszHead) ? pszHead : "options");
351
352 for (iOpt = 0; pOpt[iOpt].pszShort || pOpt[iOpt].pszLong; iOpt++) {
353
354 if (pOpt[iOpt].nFlg & GNO_FLG_SWITCH) {
355 if (pOpt[iOpt].pszShort) {
356 fprintf(stderr, "-%s ", pOpt[iOpt].pszShort);
357 }
358
359 if (pOpt[iOpt].pszLong) {
360 fprintf(stderr, "--%s", pOpt[iOpt].pszLong);
361 }
362
363 fprintf(stderr, "\n\t%s\n", (pOpt[iOpt].pszDescr)
364 ? pOpt[iOpt].pszDescr : "No description available.");
365 }
366 else {
367 if (pOpt[iOpt].pszShort) {
368 fprintf(stderr, "-%s ", pOpt[iOpt].pszShort);
369
370 fprintf(stderr, "<value> ");
371 }
372
373 if (pOpt[iOpt].pszLong) {
374 fprintf(stderr, "--%s", pOpt[iOpt].pszLong);
375
376 fprintf(stderr, "=<value>");
377 }
378
379 fprintf(stderr, "\n\t%s\n", (pOpt[iOpt].pszDescr)
380 ? pOpt[iOpt].pszDescr : "No description available.");
381 }
382 }
383
384 }
385
386 /******************************* END OF FILE **************************/
387