GRASS Programmer's Manual  6.4.2(2012)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
opt.c
Go to the documentation of this file.
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 
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 
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 
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 
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 
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  *--------------------------------------------------------------------*/
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  *--------------------------------------------------------------------*/
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 **************************/