1 /***************************************************************************
2  $RCSfile$
3                              -------------------
4     cvs         : $Id$
5     begin       : Sat Apr 24 2004
6     copyright   : (C) 2004 by Martin Preuss
7     email       : martin@libchipcard.de
8 
9  ***************************************************************************
10  *                                                                         *
11  *   This library is free software; you can redistribute it and/or         *
12  *   modify it under the terms of the GNU Lesser General Public            *
13  *   License as published by the Free Software Foundation; either          *
14  *   version 2.1 of the License, or (at your option) any later version.    *
15  *                                                                         *
16  *   This library is distributed in the hope that it will be useful,       *
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
19  *   Lesser General Public License for more details.                       *
20  *                                                                         *
21  *   You should have received a copy of the GNU Lesser General Public      *
22  *   License along with this library; if not, write to the Free Software   *
23  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
24  *   MA  02111-1307  USA                                                   *
25  *                                                                         *
26  ***************************************************************************/
27 
28 
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32 
33 #include "args_p.h"
34 #include "gui_l.h"
35 #include <gwenhywfar/misc.h>
36 #include <gwenhywfar/debug.h>
37 #include <gwenhywfar/text.h>
38 #include <string.h>
39 
40 #define DISABLE_DEBUGLOG
41 
42 
43 
44 
GWEN_Args_Check(int argc,char ** argv,int startAt,uint32_t mode,const GWEN_ARGS * args,GWEN_DB_NODE * db)45 int GWEN_Args_Check(int argc, char **argv,
46                     int startAt,
47                     uint32_t mode,
48                     const GWEN_ARGS *args,
49                     GWEN_DB_NODE *db)
50 {
51   int i;
52   const char *p;
53   const GWEN_ARGS *tmpArgs;
54   GWEN_DB_NODE *counts;
55   GWEN_BUFFER *tbuf;
56   int stop;
57 
58   i=startAt;
59 
60   tbuf=GWEN_Buffer_new(0, 256, 0, 1);
61   counts=GWEN_DB_Group_new("counts");
62 
63   stop=0;
64   while (i<argc && !stop) {
65     GWEN_ARGS_ELEMENT_TYPE t;
66     char *tmpBuf;
67     const char *v;
68     int value;
69 
70     DBG_INFO(GWEN_LOGDOMAIN, "Argument[%d] is \"%s\"", i, argv[i]);
71     if (GWEN_Gui_ReadString(argv[i], tbuf)) {
72       DBG_ERROR(GWEN_LOGDOMAIN, "Error parsing \"%s\"", argv[i]);
73       GWEN_DB_Group_free(counts);
74       GWEN_Buffer_free(tbuf);
75       return GWEN_ARGS_RESULT_ERROR;
76     }
77     p=GWEN_Buffer_GetStart(tbuf);
78     if (*p=='-') {
79       p++;
80       if (*p=='-') {
81         p++;
82         t=GWEN_ArgsElementTypeLong;
83       }
84       else
85         t=GWEN_ArgsElementTypeShort;
86     }
87     else
88       t=GWEN_ArgsElementTypeFreeParam;
89 
90     switch (t) {
91     case GWEN_ArgsElementTypeFreeParam:
92       if (mode & GWEN_ARGS_MODE_ALLOW_FREEPARAM) {
93         GWEN_DB_SetCharValue(db,
94                              GWEN_DB_FLAGS_DEFAULT,
95                              "params", p);
96         i++;
97       }
98       else {
99         DBG_ERROR(GWEN_LOGDOMAIN, "Only options are allowed, but argument \"%s\" was not recognized as a known option.", p);
100         GWEN_DB_Group_free(counts);
101         GWEN_Buffer_free(tbuf);
102         return GWEN_ARGS_RESULT_ERROR;
103       }
104       if (mode & GWEN_ARGS_MODE_STOP_AT_FREEPARAM) {
105         DBG_DEBUG(GWEN_LOGDOMAIN, "Free parameter found, stopping as requested");
106         stop=1;
107       }
108       break;
109 
110     case GWEN_ArgsElementTypeShort:
111       for (tmpArgs=args;; tmpArgs++) {
112         if (tmpArgs->shortOption) {
113           if (strcmp(tmpArgs->shortOption, p)==0) {
114             /* found option */
115             GWEN_DB_SetIntValue(counts, GWEN_DB_FLAGS_OVERWRITE_VARS,
116                                 tmpArgs->name,
117                                 GWEN_DB_GetIntValue(counts,
118                                                     tmpArgs->name, 0, 0)+1);
119             break;
120           }
121         } /* if shortOption */
122 
123         if (tmpArgs->flags & GWEN_ARGS_FLAGS_LAST) {
124           DBG_ERROR(GWEN_LOGDOMAIN, "Unknown short option \"%s\"", p);
125           GWEN_DB_Group_free(counts);
126           GWEN_Buffer_free(tbuf);
127           return GWEN_ARGS_RESULT_ERROR;
128         }
129       } /* for */
130       i++;
131 
132       if (tmpArgs->flags & GWEN_ARGS_FLAGS_HAS_ARGUMENT) {
133         /* argument needed */
134         if (i>=argc) {
135           DBG_ERROR(GWEN_LOGDOMAIN, "Argument needed for option \"%s\"", tmpArgs->name);
136           GWEN_DB_Group_free(counts);
137           GWEN_Buffer_free(tbuf);
138           return GWEN_ARGS_RESULT_ERROR;
139         }
140         GWEN_Buffer_Reset(tbuf);
141         if (GWEN_Gui_ReadString(argv[i], tbuf)) {
142           DBG_ERROR(GWEN_LOGDOMAIN, "Error parsing \"%s\"", argv[i]);
143           GWEN_DB_Group_free(counts);
144           GWEN_Buffer_free(tbuf);
145           return GWEN_ARGS_RESULT_ERROR;
146         }
147         p=GWEN_Buffer_GetStart(tbuf);
148         switch (tmpArgs->type) {
149         case GWEN_ArgsType_Char:
150           GWEN_DB_SetCharValue(db,
151                                GWEN_DB_FLAGS_DEFAULT,
152                                tmpArgs->name, p);
153           break;
154 
155         case GWEN_ArgsType_Int:
156           if (sscanf(p, "%i", &value)!=1) {
157             DBG_ERROR(GWEN_LOGDOMAIN, "Non-integer argument for short option \"%s\"",
158                       tmpArgs->shortOption);
159             GWEN_DB_Group_free(counts);
160             GWEN_Buffer_free(tbuf);
161             return GWEN_ARGS_RESULT_ERROR;
162           }
163           GWEN_DB_SetIntValue(db,
164                               GWEN_DB_FLAGS_DEFAULT,
165                               tmpArgs->name, value);
166           break;
167 
168         default:
169           DBG_ERROR(GWEN_LOGDOMAIN, "Unknown option type \"%d\"",
170                     tmpArgs->type);
171           GWEN_DB_Group_free(counts);
172           GWEN_Buffer_free(tbuf);
173           return GWEN_ARGS_RESULT_ERROR;
174         } /* switch */
175         i++;
176       }
177       else {
178         if (tmpArgs->flags & GWEN_ARGS_FLAGS_HELP) {
179           GWEN_DB_Group_free(counts);
180           GWEN_Buffer_free(tbuf);
181           return GWEN_ARGS_RESULT_HELP;
182         }
183         GWEN_DB_SetIntValue(db,
184                             GWEN_DB_FLAGS_OVERWRITE_VARS,
185                             tmpArgs->name,
186                             GWEN_DB_GetIntValue(counts, tmpArgs->name, 0, 0));
187       }
188       break;
189 
190     case GWEN_ArgsElementTypeLong:
191       /* copy option name up to (but excluding) the "=" if any,
192        * determine the start of possible argument */
193       v=p;
194       while (*v && *v!='=')
195         v++;
196       tmpBuf=(char *)malloc(v-p+1);
197       assert(tmpBuf);
198       memmove(tmpBuf, p, v-p);
199       tmpBuf[v-p]=0;
200 
201       for (tmpArgs=args;; tmpArgs++) {
202         if (tmpArgs->longOption) {
203           if (strcmp(tmpArgs->longOption, tmpBuf)==0) {
204             /* found option */
205             GWEN_DB_SetIntValue(counts, GWEN_DB_FLAGS_OVERWRITE_VARS,
206                                 tmpArgs->name,
207                                 GWEN_DB_GetIntValue(counts,
208                                                     tmpArgs->name, 0, 0)+1);
209             break;
210           }
211         } /* if longOption */
212 
213         if (tmpArgs->flags & GWEN_ARGS_FLAGS_LAST) {
214           DBG_ERROR(GWEN_LOGDOMAIN, "Unknown long option \"%s\"", tmpBuf);
215           free(tmpBuf);
216           GWEN_DB_Group_free(counts);
217           GWEN_Buffer_free(tbuf);
218           return GWEN_ARGS_RESULT_ERROR;
219         }
220       } /* for */
221       i++;
222 
223       if (*v=='=') {
224         if (!(tmpArgs->flags & GWEN_ARGS_FLAGS_HAS_ARGUMENT)) {
225           DBG_ERROR(GWEN_LOGDOMAIN, "No argument allowed for option \"%s\"",
226                     tmpArgs->name);
227           free(tmpBuf);
228           GWEN_DB_Group_free(counts);
229           GWEN_Buffer_free(tbuf);
230           return GWEN_ARGS_RESULT_ERROR;
231         }
232         v++;
233       }
234 
235       if (tmpArgs->flags & GWEN_ARGS_FLAGS_HAS_ARGUMENT) {
236         /* argument needed */
237         if (*v==0) {
238           DBG_ERROR(GWEN_LOGDOMAIN, "Argument needed for option \"%s\"", tmpArgs->name);
239           free(tmpBuf);
240           GWEN_DB_Group_free(counts);
241           GWEN_Buffer_free(tbuf);
242           return GWEN_ARGS_RESULT_ERROR;
243         }
244         switch (tmpArgs->type) {
245         case GWEN_ArgsType_Char:
246           GWEN_DB_SetCharValue(db,
247                                GWEN_DB_FLAGS_DEFAULT,
248                                tmpArgs->name, v);
249           break;
250 
251         case GWEN_ArgsType_Int:
252           if (sscanf(v, "%i", &value)!=1) {
253             DBG_ERROR(GWEN_LOGDOMAIN, "Non-integer argument for long option \"%s\"",
254                       tmpBuf);
255             free(tmpBuf);
256             GWEN_DB_Group_free(counts);
257             GWEN_Buffer_free(tbuf);
258             return GWEN_ARGS_RESULT_ERROR;
259           }
260           GWEN_DB_SetIntValue(db,
261                               GWEN_DB_FLAGS_DEFAULT,
262                               tmpArgs->name, value);
263           break;
264 
265         default:
266           DBG_ERROR(GWEN_LOGDOMAIN, "Unknown option type \"%d\"", tmpArgs->type);
267           free(tmpBuf);
268           GWEN_DB_Group_free(counts);
269           GWEN_Buffer_free(tbuf);
270           return GWEN_ARGS_RESULT_ERROR;
271         } /* switch */
272       }
273       else {
274         if (tmpArgs->flags & GWEN_ARGS_FLAGS_HELP) {
275           free(tmpBuf);
276           GWEN_DB_Group_free(counts);
277           GWEN_Buffer_free(tbuf);
278           return GWEN_ARGS_RESULT_HELP;
279         }
280         GWEN_DB_SetIntValue(db,
281                             GWEN_DB_FLAGS_OVERWRITE_VARS,
282                             tmpArgs->name,
283                             GWEN_DB_GetIntValue(counts, tmpArgs->name, 0, 0));
284       }
285       free(tmpBuf);
286 
287       break;
288 
289     default:
290       DBG_ERROR(GWEN_LOGDOMAIN, "Internal error (unknown argv type \"%d\")",
291                 t);
292       GWEN_DB_Group_free(counts);
293       GWEN_Buffer_free(tbuf);
294       return GWEN_ARGS_RESULT_ERROR;
295       break;
296     } /* switch */
297     GWEN_Buffer_Reset(tbuf);
298   } /* while */
299 
300   /* check argument counts */
301   for (tmpArgs=args;; tmpArgs++) {
302     const char *s;
303     int c;
304 
305     if (tmpArgs->longOption)
306       s=tmpArgs->longOption;
307     else
308       s=tmpArgs->shortOption;
309 
310     c=GWEN_DB_GetIntValue(counts, tmpArgs->name, 0, 0);
311 
312     /* check minnum */
313     if (tmpArgs->minNum && ((unsigned int)c<tmpArgs->minNum)) {
314       if (tmpArgs->minNum>1) {
315         DBG_ERROR(GWEN_LOGDOMAIN, "Option \"%s\" needed %d times (have %d)",
316                   s, tmpArgs->minNum, c);
317       }
318       else {
319         DBG_ERROR(GWEN_LOGDOMAIN, "Option \"%s\" needed", s);
320       }
321       GWEN_DB_Group_free(counts);
322       GWEN_Buffer_free(tbuf);
323       return GWEN_ARGS_RESULT_ERROR;
324     }
325 
326     /* check maxnum */
327     if (tmpArgs->maxNum && ((unsigned int)c>tmpArgs->maxNum)) {
328       DBG_ERROR(GWEN_LOGDOMAIN,
329                 "Option \"%s\" needed at most %d times (have %d)",
330                 s, tmpArgs->maxNum, c);
331       GWEN_DB_Group_free(counts);
332       GWEN_Buffer_free(tbuf);
333       return GWEN_ARGS_RESULT_ERROR;
334     }
335 
336     if (tmpArgs->flags & GWEN_ARGS_FLAGS_LAST)
337       break;
338   } /* for */
339   GWEN_DB_Group_free(counts);
340   GWEN_Buffer_free(tbuf);
341 
342   return i;
343 }
344 
345 
GWEN_Args__AppendTXT(GWEN_BUFFER * ubuf,const char * s,unsigned int ins)346 int GWEN_Args__AppendTXT(GWEN_BUFFER *ubuf, const char *s, unsigned int ins)
347 {
348   unsigned int i;
349 
350   while (*s) {
351     for (i=0; i<ins; i++)
352       GWEN_Buffer_AppendByte(ubuf, ' ');
353     while (*s) {
354       char c;
355 
356       c=*s;
357       s++;
358       GWEN_Buffer_AppendByte(ubuf, c);
359       if (c=='\n')
360         break;
361     } /* while */
362   } /* while */
363 
364   return 0;
365 }
366 
367 
368 
GWEN_Args_UsageTXT(const GWEN_ARGS * args,GWEN_BUFFER * ubuf)369 int GWEN_Args_UsageTXT(const GWEN_ARGS *args, GWEN_BUFFER *ubuf)
370 {
371   const GWEN_ARGS *tmpArgs;
372 
373   for (tmpArgs=args;; tmpArgs++) {
374     const char *s;
375 
376     GWEN_Buffer_AppendString(ubuf, "\n");
377     if (tmpArgs->shortOption || tmpArgs->longOption) {
378       if (tmpArgs->shortOption) {
379         GWEN_Buffer_AppendString(ubuf, " ");
380         if (tmpArgs->minNum==0)
381           GWEN_Buffer_AppendString(ubuf, "[");
382         else
383           GWEN_Buffer_AppendString(ubuf, " ");
384         GWEN_Buffer_AppendString(ubuf, "-");
385         GWEN_Buffer_AppendString(ubuf, tmpArgs->shortOption);
386         if (tmpArgs->flags & GWEN_ARGS_FLAGS_HAS_ARGUMENT)
387           GWEN_Buffer_AppendString(ubuf, " PARAM");
388         if (tmpArgs->minNum==0)
389           GWEN_Buffer_AppendString(ubuf, "]");
390         GWEN_Buffer_AppendString(ubuf, "\n");
391       } /* if short option */
392 
393       if (tmpArgs->longOption) {
394         GWEN_Buffer_AppendString(ubuf, " ");
395         if (tmpArgs->minNum==0)
396           GWEN_Buffer_AppendString(ubuf, "[");
397         else
398           GWEN_Buffer_AppendString(ubuf, " ");
399         GWEN_Buffer_AppendString(ubuf, "--");
400         GWEN_Buffer_AppendString(ubuf, tmpArgs->longOption);
401         if (tmpArgs->flags & GWEN_ARGS_FLAGS_HAS_ARGUMENT)
402           GWEN_Buffer_AppendString(ubuf, "=PARAM");
403         if (tmpArgs->minNum==0)
404           GWEN_Buffer_AppendString(ubuf, "]");
405         GWEN_Buffer_AppendString(ubuf, "\n");
406       } /* if short option */
407 
408       s=tmpArgs->longDescription;
409       if (!s)
410         s=tmpArgs->shortDescription;
411 
412       if (s) {
413         GWEN_Args__AppendTXT(ubuf, s, 3);
414         GWEN_Buffer_AppendString(ubuf, "\n");
415       }
416     } /* if any option */
417     else {
418       DBG_ERROR(GWEN_LOGDOMAIN,
419                 "Option \"%s\" has neither a long nor a short name",
420                 tmpArgs->name);
421       return -1;
422     }
423 
424     if (tmpArgs->flags & GWEN_ARGS_FLAGS_LAST)
425       break;
426   } /* for */
427 
428   return 0;
429 }
430 
431 
432 
GWEN_Args_UsageHTML(GWEN_UNUSED const GWEN_ARGS * args,GWEN_UNUSED GWEN_BUFFER * ubuf)433 int GWEN_Args_UsageHTML(GWEN_UNUSED const GWEN_ARGS *args,
434                         GWEN_UNUSED GWEN_BUFFER *ubuf)
435 {
436   return 0;
437 }
438 
439 
440 
GWEN_Args_Usage(const GWEN_ARGS * args,GWEN_BUFFER * ubuf,GWEN_ARGS_OUTTYPE ot)441 int GWEN_Args_Usage(const GWEN_ARGS *args, GWEN_BUFFER *ubuf,
442                     GWEN_ARGS_OUTTYPE ot)
443 {
444   int rv;
445 
446   switch (ot) {
447   case GWEN_ArgsOutType_Txt:
448     rv=GWEN_Args_UsageTXT(args, ubuf);
449     break;
450   case GWEN_ArgsOutType_Html:
451     rv=GWEN_Args_UsageHTML(args, ubuf);
452     break;
453   default:
454     DBG_ERROR(GWEN_LOGDOMAIN, "Unknown output type %d", ot);
455     rv=-1;
456   } /* switch */
457 
458   return rv;
459 }
460 
461 
462 
GWEN_Args_ShortUsage(GWEN_UNUSED const GWEN_ARGS * args,GWEN_UNUSED GWEN_BUFFER * ubuf,GWEN_UNUSED GWEN_ARGS_OUTTYPE ot)463 int GWEN_Args_ShortUsage(GWEN_UNUSED const GWEN_ARGS *args,
464                          GWEN_UNUSED GWEN_BUFFER *ubuf,
465                          GWEN_UNUSED GWEN_ARGS_OUTTYPE ot)
466 {
467   return 0;
468 }
469 
470 
471 
472 
473 
474 
475 
476