/[zanavi_public1]/navit/navit/maptool/libcfu-0.03-zanavi/src/cfuopt.c
ZANavi

Contents of /navit/navit/maptool/libcfu-0.03-zanavi/src/cfuopt.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Mon Feb 4 17:41:59 2013 UTC (11 years, 1 month ago) by zoff99
File MIME type: text/plain
File size: 13385 byte(s)
new map version, lots of fixes and experimental new features
1 /* Creation date: 2005-09-04 12:57:25
2 * Authors: Don
3 * Change log:
4 */
5
6 #include "cfu.h"
7 #include "cfuopt.h"
8 #include "cfuhash.h"
9 #include "cfulist.h"
10 #include "cfustring.h"
11
12 #include <stdlib.h>
13
14 #ifdef CFU_DEBUG
15 #ifdef NDEBUG
16 #undef NDEBUG
17 #endif
18 #else
19 #ifndef NDEBUG
20 #define NDEBUG 1
21 #endif
22 #endif
23 #include <assert.h>
24
25 struct cfuopt_struct {
26 libcfu_type type;
27 cfulist_t *option_list;
28 cfuhash_table_t *option_map;
29 cfulist_t *extra;
30 char *progname;
31 };
32
33 typedef enum {
34 cfuopt_arg_invalid = 0,
35 cfuopt_arg_bool,
36 cfuopt_arg_string,
37 cfuopt_arg_int,
38 cfuopt_arg_float,
39 cfuopt_arg_string_array
40 } cfuopt_arg_t;
41
42 typedef struct cfuopt_list_entry {
43 const char *arg_data;
44 const char *description;
45 const char *arg_description;
46 cfuopt_arg_t arg_type;
47 int required;
48 cfulist_t *param_names;
49 } cfuopt_list_entry_t;
50
51 #define CFU_OPT_ALLOC(type, count) (type *)calloc(count, sizeof(type));
52
53 extern cfuopt_t *
54 cfuopt_new() {
55 cfuopt_t *context = (cfuopt_t *)calloc(1, sizeof(cfuopt_t));
56 context->option_list = cfulist_new();
57 context->option_map = cfuhash_new();
58 context->extra = cfulist_new();
59 return context;
60 }
61
62 #define CFUOPT_SET_TYPE(spec, type_var) \
63 switch (spec) { \
64 case 's': \
65 type_var = cfuopt_arg_string; \
66 break; \
67 case 'i': \
68 type_var = cfuopt_arg_int; \
69 break; \
70 case 'f': \
71 type_var = cfuopt_arg_float; \
72 break; \
73 case '!': \
74 type_var = cfuopt_arg_bool; \
75 default: \
76 break; \
77 }
78
79
80 /*
81 Parse a string like Perl's Getopt::Long takes, e.g.
82
83 "verbose|v!",
84 "file|f=s",
85 "scale:f",
86 "count:i"
87
88 ! means boolean flag
89 = means required
90 : means optional
91 s means arbitrary string (C string)
92 f means float (double)
93 i means integer (long)
94
95 */
96 static void
97 parse_opt_str(const char *opt_str, cfulist_t **param_list, cfuopt_arg_t *type, int *is_required) {
98 cfulist_t *params = cfulist_new();
99 size_t num_names = 0;
100 char **opt_names = cfustring_c_str_split(opt_str, &num_names, 0, "|", NULL);
101 char *last_opt = NULL;
102 char *pos = NULL;
103 size_t opt_len = 0;
104 cfuopt_arg_t arg_type = cfuopt_arg_invalid;
105 int required = 0;
106 size_t i = 0;
107
108 if (num_names == 0) {
109 cfulist_destroy(params);
110 free(opt_names);
111 return;
112 }
113
114 last_opt = opt_names[num_names - 1];
115 opt_len = strlen(last_opt);
116 if ( (pos = memchr((void *)last_opt, '=', opt_len)) ) {
117 char *tmp = pos;
118 required = 1;
119 tmp++;
120 if (*tmp) {
121 CFUOPT_SET_TYPE(*tmp, arg_type);
122 *pos = '\000';
123 }
124 else {
125 arg_type = cfuopt_arg_invalid;
126 }
127 }
128 else if ( (pos = memchr((void *)last_opt, ':', opt_len)) ) {
129 char *tmp = pos;
130 required = 0;
131 tmp++;
132 if (*tmp) {
133 CFUOPT_SET_TYPE(*tmp, arg_type);
134 *pos = '\000';
135 }
136 else {
137 arg_type = cfuopt_arg_invalid;
138 }
139 }
140 else if ( (pos = memchr((void *)last_opt, '!', opt_len)) ) {
141 required = 0;
142 arg_type = cfuopt_arg_bool;
143 *pos = '\000';
144 }
145
146 for (i = 0; i < num_names; i++) {
147 cfulist_push(params, opt_names[i]);
148 }
149
150 free(opt_names);
151 *type = arg_type;
152 *param_list = params;
153 *is_required = required;
154 }
155
156 static void
157 _simple_list_free_fn(void *data) {
158 free(data);
159 }
160
161 struct _add_entry_struct {
162 cfuopt_t *context;
163 cfuopt_list_entry_t *entry;
164 };
165
166 static int
167 _add_to_option_map(void *data, size_t data_size, void *arg) {
168 struct _add_entry_struct *es = (struct _add_entry_struct *)arg;
169 data_size = data_size;
170
171 cfuhash_put(es->context->option_map, (char *)data, (void *)es->entry);
172
173 return 0;
174 }
175
176 extern void
177 cfuopt_add_entry(cfuopt_t *context, const char *opt_str, void *arg_data,
178 const char *description, const char *arg_description) {
179 cfuopt_list_entry_t *entry = CFU_OPT_ALLOC(cfuopt_list_entry_t, 1);
180 cfulist_t *param_list = NULL;
181 cfuopt_arg_t arg_type = cfuopt_arg_invalid;
182 struct _add_entry_struct entry_struct;
183 int required = 0;
184
185 parse_opt_str(opt_str, &param_list, &arg_type, &required);
186
187 entry->arg_data = arg_data;
188 entry->description = description;
189 entry->arg_description = arg_description;
190 entry->arg_type = arg_type;
191 entry->required = required;
192 entry->param_names = param_list;
193
194 cfulist_push(context->option_list, (void *)entry);
195
196 entry_struct.entry = entry;
197 entry_struct.context = context;
198
199 cfulist_foreach(param_list, _add_to_option_map, &entry_struct);
200 }
201
202 static void
203 check_arg(const char *arg, int *is_long, int *is_short, int *is_data, int *is_end_of_options,
204 char **parsed_arg, const char **value) {
205 const char *ptr = NULL;
206
207 ptr = arg;
208 *is_long = 0;
209 *is_short = 0;
210 *is_data = 0;
211 *is_end_of_options = 0;
212 *parsed_arg = NULL;
213 *value = NULL;
214
215 if (!ptr || !*ptr) return;
216
217 if (*ptr != '-') {
218 *is_data = 1;
219 *parsed_arg = cfustring_dup_c_str(ptr);
220 return;
221 }
222 ptr++;
223 if (!*ptr) {
224 *is_data = 1;
225 *parsed_arg = cfustring_dup_c_str(ptr - 1);
226 return;
227 }
228 if (*ptr == '-') {
229 const char *val_ptr = NULL;
230 ptr++;
231 if (!*ptr) {
232 *is_end_of_options = 1;
233 return;
234 }
235 *is_long = 1;
236 *parsed_arg = cfustring_dup_c_str(ptr);
237 val_ptr = ptr;
238 for (val_ptr = ptr; *val_ptr && *val_ptr != '='; val_ptr++);
239 if (*val_ptr == '=') {
240 (*parsed_arg)[val_ptr - ptr] = '\000';
241 val_ptr++;
242 *value = val_ptr;
243 }
244 return;
245 } else {
246 *is_short = 1;
247 *parsed_arg = cfustring_dup_c_str(ptr);
248 return;
249 }
250 }
251
252 static void
253 _set_entry_val(cfuopt_list_entry_t *entry, const char *value) {
254 switch (entry->arg_type) {
255 case cfuopt_arg_bool:
256 if (entry->arg_data) *((int *)entry->arg_data) = 1;
257 break;
258 case cfuopt_arg_int:
259 if (entry->arg_data) *((int *)entry->arg_data) = atol((char *)value);
260 break;
261 case cfuopt_arg_float:
262 if (entry->arg_data) *((double *)entry->arg_data) = atof((char *)value);
263 break;
264 case cfuopt_arg_string:
265 if (entry->arg_data) *((char **)entry->arg_data) = cfustring_dup_c_str((char *)value);
266 break;
267 default:
268 break;
269 }
270
271 }
272
273 typedef struct {
274 int count;
275 char **argv;
276 } _update_extra_ds;
277
278 static int
279 _update_extra(void *data, size_t data_size, void *arg) {
280 _update_extra_ds *ds = (_update_extra_ds *)arg;
281 data_size = data_size;
282 ds->argv[ds->count] = (char *)data;
283 ds->count++;
284
285 return 0;
286 }
287
288 extern void
289 cfuopt_parse(cfuopt_t *context, int *argc, char ***argv, char **error) {
290 int i = 0;
291 char **args = *argv;
292 int is_long_opt = 0;
293 int is_short_opt = 0;
294 int is_data = 0;
295 int is_end_of_opt = 0;
296 char *parsed_arg = NULL;
297 const char *value = NULL;
298 cfuopt_list_entry_t *entry = NULL;
299 size_t extra_count = 0;
300
301 error = error;
302
303 if (!context) return;
304 if (*argc < 1) return;
305
306 context->progname = cfustring_dup_c_str(args[0]);
307
308 if (*argc < 2) return;
309
310 for (i = 1; i < *argc; i++) {
311 char *cur_arg = args[i];
312 entry = NULL;
313 value = NULL;
314
315 if (parsed_arg) free(parsed_arg);
316 parsed_arg = NULL;
317
318 check_arg(cur_arg, &is_long_opt, &is_short_opt, &is_data, &is_end_of_opt, &parsed_arg,
319 &value);
320 if (is_long_opt || is_short_opt) {
321 entry = (cfuopt_list_entry_t *)cfuhash_get(context->option_map, parsed_arg);
322 if (parsed_arg) free(parsed_arg);
323 parsed_arg = NULL;
324 }
325 else if (is_end_of_opt) {
326 if (parsed_arg) free(parsed_arg);
327 parsed_arg = NULL;
328 i++;
329 for (; i < *argc; i++) {
330 cfulist_push(context->extra, args[i]);
331 }
332 break;
333 }
334 else if (is_data) {
335 if (parsed_arg) free(parsed_arg);
336 parsed_arg = NULL;
337 cfulist_push(context->extra, args[i]);
338 continue;
339 }
340
341 if (!entry) {
342 /* FIXME: return error here if need be */
343 continue;
344 }
345
346 switch (entry->arg_type) {
347 case cfuopt_arg_bool:
348 _set_entry_val(entry, "1");
349 break;
350 case cfuopt_arg_string:
351 case cfuopt_arg_int:
352 case cfuopt_arg_float:
353 if (value) {
354 if (entry->arg_data) {
355 _set_entry_val(entry, value);
356 }
357 } else {
358 i++;
359 if (i >= *argc) break; /* FIXME: set up error msg here */
360 check_arg(args[i], &is_long_opt, &is_short_opt, &is_data, &is_end_of_opt,
361 &parsed_arg, &value);
362 if (!is_data) {
363 i--;
364 break; /* FIXME: set up error msg here */
365 }
366 _set_entry_val(entry, parsed_arg);
367 free(parsed_arg);
368 parsed_arg = NULL;
369 }
370 break;
371 case cfuopt_arg_string_array:
372 break;
373 case cfuopt_arg_invalid:
374 /* FIXME: really should produce an error msg here */
375 break;
376 default:
377 break;
378 }
379
380 }
381
382 extra_count = cfulist_num_entries(context->extra);
383 *argc = extra_count + 1;
384 {
385 _update_extra_ds ds;
386 size_t update_count = 0;
387 ds.count = 1;
388 ds.argv = args;
389 update_count = cfulist_foreach(context->extra, _update_extra, (void *)&ds);
390 assert(update_count + 1 == (unsigned)*argc);
391 }
392 }
393
394 static void
395 _opt_list_free_fn(void *data) {
396 cfuopt_list_entry_t *entry = (cfuopt_list_entry_t *)data;
397 cfulist_destroy_with_free_fn(entry->param_names, _simple_list_free_fn);
398 free(data);
399 }
400
401 extern void
402 cfuopt_destroy(cfuopt_t *context) {
403 if (!context) return;
404 cfulist_destroy_with_free_fn(context->option_list, _opt_list_free_fn);
405 cfuhash_destroy(context->option_map);
406 cfulist_destroy(context->extra);
407 free(context->progname);
408 free(context);
409 }
410
411 #define ARG_TYPE_TO_STR(type, str) \
412 switch(type) { \
413 case cfuopt_arg_invalid: \
414 str = "INVALID"; \
415 break; \
416 case cfuopt_arg_bool: \
417 str = "BOOL"; \
418 break; \
419 case cfuopt_arg_string: \
420 str = "STRING"; \
421 break; \
422 case cfuopt_arg_int: \
423 str = "INT"; \
424 break; \
425 case cfuopt_arg_float: \
426 str = "FLOAT"; \
427 break; \
428 case cfuopt_arg_string_array: \
429 str = "STRING ARRAY"; \
430 break; \
431 default: \
432 str = "INVALID"; \
433 break; \
434 }
435
436 static int
437 _cfuopt_pretty_print_foreach(void *key, size_t key_size, void *data, size_t data_size, void *arg) {
438 char *name = (char *)key;
439 cfuopt_list_entry_t *list_entry = data;
440 char *str = NULL;
441
442 key_size = key_size;
443 data_size = data_size;
444 arg = arg;
445 ARG_TYPE_TO_STR(list_entry->arg_type, str);
446 printf("%s=%p (%s - %s) => %s, \"%s\"\n", name, (void *)list_entry, (list_entry->required ? "required" : "optional"), str, list_entry->description, list_entry->arg_description);
447
448 return 0;
449 }
450
451 extern void
452 cfuopt_pretty_print(cfuopt_t *context) {
453 cfuhash_foreach(context->option_map, _cfuopt_pretty_print_foreach, NULL);
454 }
455
456 static void
457 _list_simple_free_fn(void *data) {
458 free(data);
459 }
460
461 extern void *
462 _param_map_fn(void *data, size_t data_size, void *arg, size_t *new_data_size) {
463 char *name = (char *)data;
464 size_t len = 0;
465 cfuopt_list_entry_t *opt = (cfuopt_list_entry_t *)arg;
466
467 data_size = data_size;
468 if (!name) return NULL;
469 len = strlen(name);
470 *new_data_size = -1;
471 if (len == 0) return cfustring_dup_c_str("");
472
473 if (opt->arg_description && strlen(opt->arg_description) > 0) {
474 if (len == 1) {
475 return cfustring_sprintf_c_str("-%s %s", name, opt->arg_description);
476 }
477 else {
478 return cfustring_sprintf_c_str("--%s=%s", name, opt->arg_description);
479 }
480 }
481 else {
482 if (len == 1) {
483 return cfustring_sprintf_c_str("-%s", name);
484 }
485 else {
486 return cfustring_sprintf_c_str("--%s", name);
487 }
488 }
489
490 return NULL;
491 }
492
493 typedef struct _find_foreach_struct {
494 cfulist_t *desc_list;
495 size_t max_size;
496 } _find_foreach_ds;
497
498 typedef struct _cfuopt_desc_struct {
499 char *desc;
500 cfuopt_list_entry_t *entry;
501 } _cfuopt_desc;
502
503 static int
504 _find_foreach_fn(void *data, size_t data_size, void *arg) {
505 cfuopt_list_entry_t *opt = (cfuopt_list_entry_t *)data;
506 _find_foreach_ds *ds = (_find_foreach_ds *)arg;
507 size_t this_size = 0;
508 cfulist_t *param_full_list = NULL;
509 char *desc = NULL;
510 _cfuopt_desc *desc_ds = CFU_OPT_ALLOC(_cfuopt_desc, 1);
511
512 if (!data) return 0;
513
514 param_full_list = cfulist_map(opt->param_names, _param_map_fn, opt);
515 desc = cfulist_join(param_full_list, ", ");
516
517 data_size = data_size;
518
519 cfulist_destroy_with_free_fn(param_full_list, _simple_list_free_fn);
520
521 desc_ds->desc = desc;
522 desc_ds->entry = opt;
523 cfulist_push(ds->desc_list, desc_ds);
524
525 this_size = strlen(desc);
526 if (this_size > ds->max_size) ds->max_size = this_size;
527
528 return 0;
529 }
530
531 static size_t
532 _find_longest_help_desc(cfuopt_t *context, cfulist_t **desc_list) {
533 _find_foreach_ds ds;
534 ds.max_size = 0;
535 ds.desc_list = cfulist_new();
536
537 cfulist_foreach(context->option_list, _find_foreach_fn, (void *)&ds);
538 *desc_list = ds.desc_list;
539
540 return ds.max_size;
541 }
542
543 typedef struct {
544 char *fmt;
545 cfulist_t *list;
546 cfulist_t *desc_list;
547 } _help_lines_ds;
548
549 static int
550 _get_help_lines(void *data, size_t data_size, void *arg) {
551 _cfuopt_desc *desc_ds = (_cfuopt_desc *)data;
552 _help_lines_ds *ds = (_help_lines_ds *)arg;
553 char *left_col = NULL;
554 const char *desc = NULL;
555 char *line = NULL;
556
557 data_size = data_size;
558
559 left_col = desc_ds->desc;
560
561 if (!left_col) return 0;
562
563 desc = desc_ds->entry->description;
564 if (!desc) desc = "test desc";
565
566 line = cfustring_sprintf_c_str(ds->fmt, left_col, desc);
567 cfulist_push(ds->list, (void *)line);
568
569 return 0;
570
571 }
572
573 static void
574 _desc_list_free(void *data) {
575 _cfuopt_desc *desc_ds = (_cfuopt_desc *)data;
576 free(desc_ds->desc);
577 free(data);
578 }
579
580 extern char *
581 cfuopt_get_help_str(cfuopt_t *context) {
582 cfulist_t *desc_list = NULL;
583 size_t max_width = 0;
584 char *fmt = NULL;
585 _help_lines_ds ds;
586 char *help_str = NULL;
587
588 max_width = _find_longest_help_desc(context, &desc_list);
589
590 fmt = cfustring_sprintf_c_str(" %%-%us %%s\n", max_width);
591 ds.fmt = fmt;
592 ds.list = cfulist_new();
593 ds.desc_list = desc_list;
594
595 cfulist_foreach(desc_list, _get_help_lines, (void *)&ds);
596
597 help_str = cfulist_join(ds.list, "\n");
598
599 cfulist_destroy_with_free_fn(ds.list, _list_simple_free_fn);
600 cfulist_destroy_with_free_fn(desc_list, _desc_list_free);
601 free(fmt);
602
603 return help_str;
604 }

   
Visit the ZANavi Wiki