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