gwenhywfar  5.10.1
src/base/args.c
Go to the documentation of this file.
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 
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);
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) {
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  }
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 */
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:
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  }
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  }
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 */
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:
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  }
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  }
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)) {
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 
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 
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 {
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 
434  GWEN_UNUSED GWEN_BUFFER *ubuf)
435 {
436  return 0;
437 }
438 
439 
440 
441 int GWEN_Args_Usage(const GWEN_ARGS *args, GWEN_BUFFER *ubuf,
443 {
444  int rv;
445 
446  switch (ot) {
448  rv=GWEN_Args_UsageTXT(args, ubuf);
449  break;
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 
464  GWEN_UNUSED GWEN_BUFFER *ubuf,
466 {
467  return 0;
468 }
469 
470 
471 
472 
473 
474 
475 
int GWEN_Args__AppendTXT(GWEN_BUFFER *ubuf, const char *s, unsigned int ins)
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition: buffer.c:235
const char * shortDescription
Definition: src/base/args.h:87
#define GWEN_DB_FLAGS_OVERWRITE_VARS
Definition: db.h:121
struct GWEN_DB_NODE GWEN_DB_NODE
Definition: db.h:228
void GWEN_DB_Group_free(GWEN_DB_NODE *n)
Definition: db.c:421
unsigned int maxNum
Definition: src/base/args.h:84
const char * longOption
Definition: src/base/args.h:86
#define GWEN_LOGDOMAIN
Definition: logger.h:35
#define GWEN_ARGS_FLAGS_HELP
Definition: src/base/args.h:52
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition: buffer.c:42
int GWEN_Args_UsageHTML(GWEN_UNUSED const GWEN_ARGS *args, GWEN_UNUSED GWEN_BUFFER *ubuf)
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition: buffer.c:650
#define GWEN_ARGS_RESULT_HELP
Definition: src/base/args.h:58
int GWEN_Args_UsageTXT(const GWEN_ARGS *args, GWEN_BUFFER *ubuf)
#define GWEN_ARGS_RESULT_ERROR
Definition: src/base/args.h:57
#define GWEN_ARGS_MODE_STOP_AT_FREEPARAM
Definition: src/base/args.h:55
const char * longDescription
Definition: src/base/args.h:88
int GWEN_Args_ShortUsage(GWEN_UNUSED const GWEN_ARGS *args, GWEN_UNUSED GWEN_BUFFER *ubuf, GWEN_UNUSED GWEN_ARGS_OUTTYPE ot)
unsigned int minNum
Definition: src/base/args.h:83
#define DBG_DEBUG(dbg_logger, format, args...)
Definition: debug.h:214
int GWEN_Args_Usage(const GWEN_ARGS *args, GWEN_BUFFER *ubuf, GWEN_ARGS_OUTTYPE ot)
#define GWEN_ARGS_MODE_ALLOW_FREEPARAM
Definition: src/base/args.h:54
int GWEN_Buffer_AppendByte(GWEN_BUFFER *bf, char c)
Definition: buffer.c:394
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition: buffer.c:89
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition: buffer.h:38
#define GWEN_ARGS_FLAGS_LAST
Definition: src/base/args.h:51
GWEN_ARGS_TYPE type
Definition: src/base/args.h:81
GWEN_ARGS_OUTTYPE
Definition: src/base/args.h:67
int GWEN_Gui_ReadString(const char *text, GWEN_BUFFER *tbuf)
Definition: gui_utils.c:183
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
int GWEN_Args_Check(int argc, char **argv, int startAt, uint32_t mode, const GWEN_ARGS *args, GWEN_DB_NODE *db)
Definition: src/base/args.c:45
int GWEN_DB_SetCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val)
Definition: db.c:997
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
int GWEN_DB_GetIntValue(GWEN_DB_NODE *n, const char *path, int idx, int defVal)
Definition: db.c:1163
uint32_t flags
Definition: src/base/args.h:80
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition: db.c:173
const char * shortOption
Definition: src/base/args.h:85
int GWEN_DB_SetIntValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, int val)
Definition: db.c:1202
#define GWEN_ARGS_FLAGS_HAS_ARGUMENT
Definition: src/base/args.h:50
#define GWEN_UNUSED
const char * name
Definition: src/base/args.h:82
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:989
#define GWEN_DB_FLAGS_DEFAULT
Definition: db.h:168