Initial import to Tizen
[profile/ivi/sphinxbase.git] / src / libsphinxbase / util / cmd_ln.c
1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3  * Copyright (c) 1999-2004 Carnegie Mellon University.  All rights
4  * reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * This work was supported in part by funding from the Defense Advanced 
19  * Research Projects Agency and the National Science Foundation of the 
20  * United States of America, and the CMU Sphinx Speech Consortium.
21  *
22  * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND 
23  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
24  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26  * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
28  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
32  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * ====================================================================
35  *
36  */
37 /*
38  * cmd_ln.c -- Command line argument parsing.
39  *
40  * **********************************************
41  * CMU ARPA Speech Project
42  *
43  * Copyright (c) 1999 Carnegie Mellon University.
44  * ALL RIGHTS RESERVED.
45  * **********************************************
46  * 
47  * HISTORY
48  * 
49  * 10-Sep-1998  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
50  *              Changed strcasecmp() call in cmp_name() to strcmp_nocase() call.
51  * 
52  * 15-Jul-1997  M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
53  *              Added required arguments handling.
54  * 
55  * 07-Dec-96    M K Ravishankar (rkm@cs.cmu.edu) at Carnegie Mellon University
56  *              Created, based on Eric's implementation.  Basically, combined several
57  *              functions into one, eliminated validation, and simplified the interface.
58  */
59
60
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <assert.h>
65
66 #ifdef _MSC_VER
67 #pragma warning (disable: 4996 4018)
68 #endif
69
70 #ifdef HAVE_CONFIG_H
71 #include <config.h>
72 #endif
73
74 #ifdef HAVE_UNISTD_H
75 #include <unistd.h>
76 #endif
77
78 #include "sphinxbase/cmd_ln.h"
79 #include "sphinxbase/err.h"
80 #include "sphinxbase/ckd_alloc.h"
81 #include "sphinxbase/hash_table.h"
82 #include "sphinxbase/case.h"
83 #include "sphinxbase/strfuncs.h"
84
85 typedef struct cmd_ln_val_s {
86     anytype_t val;
87     int type;
88 } cmd_ln_val_t;
89
90 struct cmd_ln_s {
91     int refcount;
92     hash_table_t *ht;
93     char **f_argv;
94     uint32 f_argc;
95 };
96
97 /** Global command-line, for non-reentrant API. */
98 cmd_ln_t *global_cmdln;
99 static void arg_dump_r(cmd_ln_t *cmdln, FILE * fp, arg_t const *defn, int32 doc);
100 static cmd_ln_t * parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict);
101
102 /*
103  * Find max length of name and default fields in the given defn array.
104  * Return #items in defn array.
105  */
106 static int32
107 arg_strlen(const arg_t * defn, int32 * namelen, int32 * deflen)
108 {
109     int32 i, l;
110
111     *namelen = *deflen = 0;
112     for (i = 0; defn[i].name; i++) {
113         l = strlen(defn[i].name);
114         if (*namelen < l)
115             *namelen = l;
116
117         if (defn[i].deflt)
118             l = strlen(defn[i].deflt);
119         else
120             l = strlen("(null)");
121         /*      E_INFO("string default, %s , name %s, length %d\n",defn[i].deflt,defn[i].name,l); */
122         if (*deflen < l)
123             *deflen = l;
124     }
125
126     return i;
127 }
128
129
130 static int32
131 cmp_name(const void *a, const void *b)
132 {
133     return (strcmp_nocase
134             ((* (arg_t**) a)->name,
135              (* (arg_t**) b)->name));
136 }
137
138 static const arg_t **
139 arg_sort(const arg_t * defn, int32 n)
140 {
141     const arg_t ** pos;
142     int32 i;
143
144     pos = (const arg_t **) ckd_calloc(n, sizeof(arg_t *));
145     for (i = 0; i < n; ++i)
146         pos[i] = &defn[i];
147     qsort(pos, n, sizeof(arg_t *), cmp_name);
148
149     return pos;
150 }
151
152 static size_t
153 strnappend(char **dest, size_t *dest_allocation, 
154        const char *source, size_t n)
155 {
156     size_t source_len, required_allocation;
157
158     if (dest == NULL || dest_allocation == NULL)
159         return -1;
160     if (*dest == NULL && *dest_allocation != 0)
161         return -1;
162     if (source == NULL)
163         return *dest_allocation;
164
165     source_len = strlen(source);
166     if (n && n < source_len)
167         source_len = n;
168
169     required_allocation = (*dest ? strlen(*dest) : 0) + source_len + 1;
170     if (*dest_allocation < required_allocation) {
171         if (*dest_allocation == 0) {
172             *dest = ckd_calloc(required_allocation * 2, 1);
173         } else {
174             *dest = ckd_realloc(*dest, required_allocation * 2);
175         }
176         *dest_allocation = required_allocation * 2;
177     } 
178
179     strncat(*dest, source, source_len);
180
181     return *dest_allocation;
182 }
183
184 static size_t
185 strappend(char **dest, size_t *dest_allocation, 
186        const char *source)
187 {
188     return strnappend(dest, dest_allocation, source, 0);
189 }
190
191 static char*
192 arg_resolve_env(const char *str)
193 {
194     char *resolved_str = NULL;
195     char env_name[100];
196     const char *env_val;
197     size_t alloced = 0;
198     const char *i = str, *j;
199
200     /* calculate required resolved_str size */
201     do {
202         j = strstr(i, "$(");
203         if (j != NULL) {
204             if (j != i) {
205                 strnappend(&resolved_str, &alloced, i, j - i);
206                 i = j;
207             }
208             j = strchr(i + 2, ')');
209             if (j != NULL) {
210                 if (j - (i + 2) < 100) {
211                     strncpy(env_name, i + 2, j - (i + 2));
212                     env_name[j - (i + 2)] = '\0';
213                     #if !defined(_WIN32_WCE)
214                     env_val = getenv(env_name);
215                     if (env_val)
216                         strappend(&resolved_str, &alloced, env_val);
217                     #else
218                     env_val = 0;
219                     #endif
220                 }
221                 i = j + 1;
222             } else {
223                 /* unclosed, copy and skip */
224                 j = i + 2;
225                 strnappend(&resolved_str, &alloced, i, j - i);
226                 i = j;
227             }
228         } else {
229             strappend(&resolved_str, &alloced, i);
230         }
231     } while(j != NULL);
232
233     return resolved_str;
234 }
235
236 static void
237 arg_dump_r(cmd_ln_t *cmdln, FILE * fp, const arg_t * defn, int32 doc)
238 {
239     const arg_t **pos;
240     int32 i, l, n;
241     int32 namelen, deflen;
242     anytype_t *vp;
243     char const **array;
244
245     /* No definitions, do nothing. */
246     if (defn == NULL)
247         return;
248     if (fp == NULL)
249         return;
250
251     /* Find max lengths of name and default value fields, and #entries in defn */
252     n = arg_strlen(defn, &namelen, &deflen);
253     /*    E_INFO("String length %d. Name length %d, Default Length %d\n",n, namelen, deflen); */
254     namelen = namelen & 0xfffffff8;     /* Previous tab position */
255     deflen = deflen & 0xfffffff8;       /* Previous tab position */
256
257     fprintf(fp, "[NAME]");
258     for (l = strlen("[NAME]"); l < namelen; l += 8)
259         fprintf(fp, "\t");
260     fprintf(fp, "\t[DEFLT]");
261     for (l = strlen("[DEFLT]"); l < deflen; l += 8)
262         fprintf(fp, "\t");
263
264     if (doc) {
265         fprintf(fp, "\t[DESCR]\n");
266     }
267     else {
268         fprintf(fp, "\t[VALUE]\n");
269     }
270
271     /* Print current configuration, sorted by name */
272     pos = arg_sort(defn, n);
273     for (i = 0; i < n; i++) {
274         fprintf(fp, "%s", pos[i]->name);
275         for (l = strlen(pos[i]->name); l < namelen; l += 8)
276             fprintf(fp, "\t");
277
278         fprintf(fp, "\t");
279         if (pos[i]->deflt) {
280             fprintf(fp, "%s", pos[i]->deflt);
281             l = strlen(pos[i]->deflt);
282         }
283         else
284             l = 0;
285         for (; l < deflen; l += 8)
286             fprintf(fp, "\t");
287
288         fprintf(fp, "\t");
289         if (doc) {
290             if (pos[i]->doc)
291                 fprintf(fp, "%s", pos[i]->doc);
292         }
293         else {
294             vp = cmd_ln_access_r(cmdln, pos[i]->name);
295             if (vp) {
296                 switch (pos[i]->type) {
297                 case ARG_INTEGER:
298                 case REQARG_INTEGER:
299                     fprintf(fp, "%ld", vp->i);
300                     break;
301                 case ARG_FLOATING:
302                 case REQARG_FLOATING:
303                     fprintf(fp, "%e", vp->fl);
304                     break;
305                 case ARG_STRING:
306                 case REQARG_STRING:
307                     if (vp->ptr)
308                         fprintf(fp, "%s", (char *)vp->ptr);
309                     break;
310                 case ARG_STRING_LIST:
311                     array = (char const**)vp->ptr;
312                     if (array)
313                         for (l = 0; array[l] != 0; l++) {
314                             fprintf(fp, "%s,", array[l]);
315                         }
316                     break;
317                 case ARG_BOOLEAN:
318                 case REQARG_BOOLEAN:
319                     fprintf(fp, "%s", vp->i ? "yes" : "no");
320                     break;
321                 default:
322                     E_ERROR("Unknown argument type: %d\n", pos[i]->type);
323                 }
324             }
325         }
326
327         fprintf(fp, "\n");
328     }
329     ckd_free(pos);
330
331     fprintf(fp, "\n");
332     fflush(fp);
333 }
334
335 static char **
336 parse_string_list(const char *str)
337 {
338     int count, i, j;
339     const char *p;
340     char ** result;
341
342     p = str;
343     count = 1;
344     while (*p) {
345         if (*p == ',')
346             count++;
347         p++;
348     }
349     /* Should end with NULL */
350     result = (char **) ckd_calloc(count + 1, sizeof(char *));
351     p = str;
352     for (i = 0; i < count; i++) {
353         for (j = 0; p[j] != ',' && p[j] != 0; j++);
354         result[i] = ckd_calloc(j + 1, sizeof(char));
355         strncpy( result[i], p, j);
356         p = p + j + 1;
357     }
358     return result;
359 }
360
361 static cmd_ln_val_t *
362 cmd_ln_val_init(int t, const char *str)
363 {
364     cmd_ln_val_t *v;
365     anytype_t val;
366     char *e_str;
367
368     if (!str) {
369         /* For lack of a better default value. */
370         memset(&val, 0, sizeof(val));
371     }
372     else {
373         int valid = 1;
374         e_str = arg_resolve_env(str);
375
376         switch (t) {
377         case ARG_INTEGER:
378         case REQARG_INTEGER:
379             if (sscanf(e_str, "%ld", &val.i) != 1)
380                 valid = 0;
381             break;
382         case ARG_FLOATING:
383         case REQARG_FLOATING:
384             if (e_str == NULL || e_str[0] == 0)
385                 valid = 0;
386             val.fl = atof_c(e_str);
387             break;
388         case ARG_BOOLEAN:
389         case REQARG_BOOLEAN:
390             if ((e_str[0] == 'y') || (e_str[0] == 't') ||
391                 (e_str[0] == 'Y') || (e_str[0] == 'T') || (e_str[0] == '1')) {
392                 val.i = TRUE;
393             }
394             else if ((e_str[0] == 'n') || (e_str[0] == 'f') ||
395                      (e_str[0] == 'N') || (e_str[0] == 'F') |
396                      (e_str[0] == '0')) {
397                 val.i = FALSE;
398             }
399             else {
400                 E_ERROR("Unparsed boolean value '%s'\n", str);
401                 valid = 0;
402             }
403             break;
404         case ARG_STRING:
405         case REQARG_STRING:
406             val.ptr = ckd_salloc(e_str);
407             break;
408         case ARG_STRING_LIST:
409             val.ptr = parse_string_list(e_str);
410             break;
411         default:
412             E_ERROR("Unknown argument type: %d\n", t);
413             valid = 0;
414         }
415
416         ckd_free(e_str);
417         if (valid == 0)
418             return NULL;
419     }
420
421     v = ckd_calloc(1, sizeof(*v));
422     memcpy(v, &val, sizeof(val));
423     v->type = t;
424
425     return v;
426 }
427
428 /*
429  * Handles option parsing for cmd_ln_parse_file_r() and cmd_ln_init()
430  * also takes care of storing argv.
431  * DO NOT call it from cmd_ln_parse_r()
432  */
433 static cmd_ln_t *
434 parse_options(cmd_ln_t *cmdln, const arg_t *defn, int32 argc, char* argv[], int32 strict)
435 {
436     cmd_ln_t *new_cmdln;
437
438     new_cmdln = cmd_ln_parse_r(cmdln, defn, argc, argv, strict);
439     /* If this failed then clean up and return NULL. */
440     if (new_cmdln == NULL) {
441         int32 i;
442         for (i = 0; i < argc; ++i)
443             ckd_free(argv[i]);
444         ckd_free(argv);
445         return NULL;
446     }
447
448     /* Otherwise, we need to add the contents of f_argv to the new object. */
449     if (new_cmdln == cmdln) {
450         /* If we are adding to a previously passed-in cmdln, then
451          * store our allocated strings in its f_argv. */
452         new_cmdln->f_argv = ckd_realloc(new_cmdln->f_argv,
453                                         (new_cmdln->f_argc + argc)
454                                         * sizeof(*new_cmdln->f_argv));
455         memcpy(new_cmdln->f_argv + new_cmdln->f_argc, argv,
456                argc * sizeof(*argv));
457         ckd_free(argv);
458         new_cmdln->f_argc += argc;
459     }
460     else {
461         /* Otherwise, store f_argc and f_argv. */
462         new_cmdln->f_argc = argc;
463         new_cmdln->f_argv = argv;
464     }
465
466     return new_cmdln;
467 }
468
469 void
470 cmd_ln_val_free(cmd_ln_val_t *val)
471 {
472     int i;
473     if (val->type & ARG_STRING_LIST) {
474         char const** array = (char const **)val->val.ptr;
475         if (array) {
476             for (i = 0; array[i] != NULL; i++) {
477                 ckd_free(val->val.ptr);
478             }
479             ckd_free(array);
480         }
481     }
482     if (val->type & ARG_STRING)
483         ckd_free(val->val.ptr);
484     ckd_free(val);
485 }
486
487 cmd_ln_t *
488 cmd_ln_get(void)
489 {
490     return global_cmdln;
491 }
492
493 void
494 cmd_ln_appl_enter(int argc, char *argv[],
495                   const char *default_argfn,
496                   const arg_t * defn)
497 {
498     /* Look for default or specified arguments file */
499     const char *str;
500
501     str = NULL;
502
503     if ((argc == 2) && (strcmp(argv[1], "help") == 0)) {
504         cmd_ln_print_help(stderr, defn);
505         exit(1);
506     }
507
508     if ((argc == 2) && (argv[1][0] != '-'))
509         str = argv[1];
510     else if (argc == 1) {
511         FILE *fp;
512         E_INFO("Looking for default argument file: %s\n", default_argfn);
513
514         if ((fp = fopen(default_argfn, "r")) == NULL) {
515             E_INFO("Can't find default argument file %s.\n",
516                    default_argfn);
517         }
518         else {
519             str = default_argfn;
520         }
521         if (fp != NULL)
522             fclose(fp);
523     }
524
525
526     if (str) {
527         /* Build command line argument list from file */
528         E_INFO("Parsing command lines from file %s\n", str);
529         if (cmd_ln_parse_file(defn, str, TRUE)) {
530             E_INFOCONT("Usage:\n");
531             E_INFOCONT("\t%s argument-list, or\n", argv[0]);
532             E_INFOCONT("\t%s [argument-file] (default file: . %s)\n\n",
533                     argv[0], default_argfn);
534             cmd_ln_print_help(stderr, defn);
535             exit(1);
536         }
537     }
538     else {
539         cmd_ln_parse(defn, argc, argv, TRUE);
540     }
541 }
542
543 void
544 cmd_ln_appl_exit()
545 {
546     cmd_ln_free();
547 }
548
549
550 cmd_ln_t *
551 cmd_ln_parse_r(cmd_ln_t *inout_cmdln, const arg_t * defn, int32 argc, char *argv[], int strict)
552 {
553     int32 i, j, n, argstart;
554     hash_table_t *defidx = NULL;
555     cmd_ln_t *cmdln;
556     
557     /* Construct command-line object */
558     if (inout_cmdln == NULL) {
559         cmdln = ckd_calloc(1, sizeof(*cmdln));
560         cmdln->refcount = 1;
561     }
562     else
563         cmdln = inout_cmdln;
564
565     /* Build a hash table for argument definitions */
566     defidx = hash_table_new(50, 0);
567     if (defn) {
568         for (n = 0; defn[n].name; n++) {
569             void *v;
570
571             v = hash_table_enter(defidx, defn[n].name, (void *)&defn[n]);
572             if (strict && (v != &defn[n])) {
573                 E_ERROR("Duplicate argument name in definition: %s\n", defn[n].name);
574                 goto error;
575             }
576         }
577     }
578     else {
579         /* No definitions. */
580         n = 0;
581     }
582
583     /* Allocate memory for argument values */
584     if (cmdln->ht == NULL)
585         cmdln->ht = hash_table_new(n, 0 /* argument names are case-sensitive */ );
586
587
588     /* skip argv[0] if it doesn't start with dash */
589     argstart = 0;
590     if (argc > 0 && argv[0][0] != '-') {
591         argstart = 1;
592     } 
593
594     /* Parse command line arguments (name-value pairs) */
595     for (j = argstart; j < argc; j += 2) {
596         arg_t *argdef;
597         cmd_ln_val_t *val;
598         void *v;
599
600         if (hash_table_lookup(defidx, argv[j], &v) < 0) {
601             if (strict) {
602                 E_ERROR("Unknown argument name '%s'\n", argv[j]);
603                 goto error;
604             }
605             else if (defn == NULL)
606                 v = NULL;
607             else
608                 continue;
609         }
610         argdef = v;
611
612         /* Enter argument value */      
613         if (j + 1 >= argc) {
614             cmd_ln_print_help_r(cmdln, stderr, defn);
615             E_ERROR("Argument value for '%s' missing\n", argv[j]);
616             goto error;
617         }
618
619         if (argdef == NULL)
620             val = cmd_ln_val_init(ARG_STRING, argv[j + 1]);
621         else {
622             if ((val = cmd_ln_val_init(argdef->type, argv[j + 1])) == NULL) {
623                 cmd_ln_print_help_r(cmdln, stderr, defn);
624                 E_ERROR("Bad argument value for %s: %s\n", argv[j],
625                         argv[j + 1]);
626                 goto error;
627             }
628         }
629
630         if ((v = hash_table_enter(cmdln->ht, argv[j], (void *)val)) != (void *)val) {
631             if (strict) {
632                 cmd_ln_val_free(val);
633                 E_ERROR("Duplicate argument name in arguments: %s\n",
634                         argdef->name);
635                 goto error;
636             }
637             else {
638                 v = hash_table_replace(cmdln->ht, argv[j], (void *)val);
639                 cmd_ln_val_free((cmd_ln_val_t *)v);
640             }
641         }
642     }
643
644     /* Fill in default values, if any, for unspecified arguments */
645     for (i = 0; i < n; i++) {
646         cmd_ln_val_t *val;
647         void *v;
648
649         if (hash_table_lookup(cmdln->ht, defn[i].name, &v) < 0) {
650             if ((val = cmd_ln_val_init(defn[i].type, defn[i].deflt)) == NULL) {
651                 E_ERROR
652                     ("Bad default argument value for %s: %s\n",
653                      defn[i].name, defn[i].deflt);
654                 goto error;
655             }
656             hash_table_enter(cmdln->ht, defn[i].name, (void *)val);
657         }
658     }
659
660     /* Check for required arguments; exit if any missing */
661     j = 0;
662     for (i = 0; i < n; i++) {
663         if (defn[i].type & ARG_REQUIRED) {
664             void *v;
665             if (hash_table_lookup(cmdln->ht, defn[i].name, &v) != 0)
666                 E_ERROR("Missing required argument %s\n", defn[i].name);
667         }
668     }
669     if (j > 0) {
670         cmd_ln_print_help_r(cmdln, stderr, defn);
671         goto error;
672     }
673
674     if (strict && argc == 1) {
675         E_ERROR("No arguments given, available options are:\n");
676         cmd_ln_print_help_r(cmdln, stderr, defn);
677         if (defidx)
678             hash_table_free(defidx);
679         if (inout_cmdln == NULL)
680             cmd_ln_free_r(cmdln);
681         return NULL;
682     }
683
684 #ifndef _WIN32_WCE
685     /* Set up logging. We need to do this earlier because we want to dump
686      * the information to the configured log, not to the stderr. */
687     if (cmd_ln_exists_r(cmdln, "-logfn") && cmd_ln_str_r(cmdln, "-logfn"))
688         err_set_logfile(cmd_ln_str_r(cmdln, "-logfn"));
689
690     /* Echo command line */
691     E_INFO("Parsing command line:\n");
692     for (i = 0; i < argc; i++) {
693         if (argv[i][0] == '-')
694             E_INFOCONT("\\\n\t");
695         E_INFOCONT("%s ", argv[i]);
696     }
697     E_INFOCONT("\n\n");
698     fflush(stderr);
699
700     /* Print configuration */
701     E_INFOCONT("Current configuration:\n");
702     arg_dump_r(cmdln, err_get_logfp(), defn, 0);
703 #endif
704
705     hash_table_free(defidx);
706     return cmdln;
707
708   error:
709     if (defidx)
710         hash_table_free(defidx);
711     if (inout_cmdln == NULL)
712         cmd_ln_free_r(cmdln);
713     E_ERROR("Failed to parse arguments list\n");
714     return NULL;
715 }
716
717 cmd_ln_t *
718 cmd_ln_init(cmd_ln_t *inout_cmdln, const arg_t *defn, int32 strict, ...)
719 {
720     va_list args;
721     const char *arg, *val;
722     char **f_argv;
723     int32 f_argc;
724
725     va_start(args, strict);
726     f_argc = 0;
727     while ((arg = va_arg(args, const char *))) {
728         ++f_argc;
729         val = va_arg(args, const char*);
730         if (val == NULL) {
731             E_ERROR("Number of arguments must be even!\n");
732             return NULL;
733         }
734         ++f_argc;
735     }
736     va_end(args);
737
738     /* Now allocate f_argv */
739     f_argv = ckd_calloc(f_argc, sizeof(*f_argv));
740     va_start(args, strict);
741     f_argc = 0;
742     while ((arg = va_arg(args, const char *))) {
743         f_argv[f_argc] = ckd_salloc(arg);
744         ++f_argc;
745         val = va_arg(args, const char*);
746         f_argv[f_argc] = ckd_salloc(val);
747         ++f_argc;
748     }
749     va_end(args);
750
751     return parse_options(inout_cmdln, defn, f_argc, f_argv, strict);
752 }
753
754 int
755 cmd_ln_parse(const arg_t * defn, int32 argc, char *argv[], int strict)
756 {
757     cmd_ln_t *cmdln;
758
759     cmdln = cmd_ln_parse_r(global_cmdln, defn, argc, argv, strict);
760     if (cmdln == NULL) {
761         /* Old, bogus behaviour... */
762         E_ERROR("Failed to parse arguments list, forced exit\n");
763         exit(-1);
764     }
765     /* Initialize global_cmdln if not present. */
766     if (global_cmdln == NULL) {
767         global_cmdln = cmdln;
768     }
769     return 0;
770 }
771
772 cmd_ln_t *
773 cmd_ln_parse_file_r(cmd_ln_t *inout_cmdln, const arg_t * defn, const char *filename, int32 strict)
774 {
775     FILE *file;
776     int argc;
777     int argv_size;
778     char *str;
779     int arg_max_length = 512;
780     int len = 0;
781     int quoting, ch;
782     char **f_argv;
783     int rv = 0;
784     const char separator[] = " \t\r\n";
785
786     if ((file = fopen(filename, "r")) == NULL) {
787         E_ERROR("Cannot open configuration file %s for reading\n",
788                 filename);
789         return NULL;
790     }
791
792     ch = fgetc(file);
793     /* Skip to the next interesting character */
794     for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
795
796     if (ch == EOF) {
797         fclose(file);
798         return NULL;
799     }
800
801     /*
802      * Initialize default argv, argc, and argv_size.
803      */
804     argv_size = 10;
805     argc = 0;
806     f_argv = ckd_calloc(argv_size, sizeof(char *));
807     /* Silently make room for \0 */
808     str = ckd_calloc(arg_max_length + 1, sizeof(char));
809     quoting = 0;
810
811     do {
812         /* Handle arguments that are commented out */
813         if (len == 0 && argc % 2 == 0) {
814             while (ch == '#') {
815                 /* Skip everything until newline */
816                 for (ch = fgetc(file); ch != EOF && ch != '\n'; ch = fgetc(file)) ;
817                 /* Skip to the next interesting character */
818                 for (ch = fgetc(file); ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
819             }
820
821             /* Check if we are at the last line (without anything interesting in it) */
822             if (ch == EOF)
823                 break;
824         }
825
826         /* Handle quoted arguments */
827         if (ch == '"' || ch == '\'') {
828             if (quoting == ch) /* End a quoted section with the same type */
829                 quoting = 0;
830             else if (quoting) {
831                 E_ERROR("Nesting quotations is not supported!\n");
832                 rv = 1;
833                 break;
834             }
835             else
836                 quoting = ch; /* Start a quoted section */
837         }
838         else if (ch == EOF || (!quoting && strchr(separator, ch))) {
839             /* Reallocate argv so it is big enough to contain all the arguments */
840             if (argc >= argv_size) {
841                 char **tmp_argv;
842                 if (!(tmp_argv =
843                        ckd_realloc(f_argv, argv_size * 2 * sizeof(char *)))) {
844                     rv = 1;
845                     break;
846                 }
847                 f_argv = tmp_argv;
848                 argv_size *= 2;
849             }
850             /* Add the string to the list of arguments */
851             f_argv[argc] = ckd_salloc(str);
852             len = 0;
853             str[0] = '\0';
854             argc++;
855
856             if (quoting)
857                 E_WARN("Unclosed quotation, having EOF close it...\n");
858
859             /* Skip to the next interesting character */
860             for (; ch != EOF && strchr(separator, ch); ch = fgetc(file)) ;
861
862             if (ch == EOF)
863                 break;
864
865             /* We already have the next character */
866             continue;
867         }
868         else {
869             if (len >= arg_max_length) {
870                 /* Make room for more chars (including the \0 !) */
871                 char *tmp_str = str;
872                 if ((tmp_str = ckd_realloc(str, (1 + arg_max_length * 2) * sizeof(char))) == NULL) {
873                     rv = 1;
874                     break;
875                 }
876                 str = tmp_str;
877                 arg_max_length *= 2;
878             }
879             /* Add the char to the argument string */
880             str[len++] = ch;
881             /* Always null terminate */
882             str[len] = '\0';
883         }
884
885         ch = fgetc(file);
886     } while (1);
887
888     fclose(file);
889
890     ckd_free(str);
891
892     if (rv) {
893         for (ch = 0; ch < argc; ++ch)
894             ckd_free(f_argv[ch]);
895         ckd_free(f_argv);
896         return NULL;
897     }
898
899     return parse_options(inout_cmdln, defn, argc, f_argv, strict);
900 }
901
902 int
903 cmd_ln_parse_file(const arg_t * defn, const char *filename, int32 strict)
904 {
905     cmd_ln_t *cmdln;
906
907     cmdln = cmd_ln_parse_file_r(global_cmdln, defn, filename, strict);
908     if (cmdln == NULL) {
909         return -1;
910     }
911     /* Initialize global_cmdln if not present. */
912     if (global_cmdln == NULL) {
913         global_cmdln = cmdln;
914     }
915     return 0;
916 }
917
918 void
919 cmd_ln_print_help_r(cmd_ln_t *cmdln, FILE * fp, arg_t const* defn)
920 {
921     if (defn == NULL)
922         return;
923     fprintf(fp, "Arguments list definition:\n");
924     arg_dump_r(cmdln, fp, defn, 1);
925     fflush(fp);
926 }
927
928 int
929 cmd_ln_exists_r(cmd_ln_t *cmdln, const char *name)
930 {
931     void *val;
932     if (cmdln == NULL)
933         return FALSE;
934     return (hash_table_lookup(cmdln->ht, name, &val) == 0);
935 }
936
937 anytype_t *
938 cmd_ln_access_r(cmd_ln_t *cmdln, const char *name)
939 {
940     void *val;
941     if (hash_table_lookup(cmdln->ht, name, &val) < 0) {
942         E_ERROR("Unknown argument: %s\n", name);
943         return NULL;
944     }
945     return (anytype_t *)val;
946 }
947
948 char const *
949 cmd_ln_str_r(cmd_ln_t *cmdln, char const *name)
950 {
951     anytype_t *val;
952     val = cmd_ln_access_r(cmdln, name);
953     if (val == NULL)
954         return NULL;
955     return (char const *)val->ptr;
956 }
957
958 char const **
959 cmd_ln_str_list_r(cmd_ln_t *cmdln, char const *name)
960 {
961     anytype_t *val;
962     val = cmd_ln_access_r(cmdln, name);
963     if (val == NULL)
964         return NULL;
965     return (char const **)val->ptr;
966 }
967
968 long
969 cmd_ln_int_r(cmd_ln_t *cmdln, char const *name)
970 {
971     anytype_t *val;
972     val = cmd_ln_access_r(cmdln, name);
973     if (val == NULL)
974         return 0L;
975     return val->i;
976 }
977
978 double
979 cmd_ln_float_r(cmd_ln_t *cmdln, char const *name)
980 {
981     anytype_t *val;
982     val = cmd_ln_access_r(cmdln, name);
983     if (val == NULL)
984         return 0.0;
985     return val->fl;
986 }
987
988 void
989 cmd_ln_set_str_r(cmd_ln_t *cmdln, char const *name, char const *str)
990 {
991     anytype_t *val;
992     val = cmd_ln_access_r(cmdln, name);
993     if (val == NULL) {
994         E_ERROR("Unknown argument: %s\n", name);
995         return;
996     }
997     ckd_free(val->ptr);
998     if (str == NULL)
999         val->ptr = NULL;
1000     else
1001         val->ptr = ckd_salloc(str);
1002 }
1003
1004 void
1005 cmd_ln_set_int_r(cmd_ln_t *cmdln, char const *name, long iv)
1006 {
1007     anytype_t *val;
1008     val = cmd_ln_access_r(cmdln, name);
1009     if (val == NULL) {
1010         E_ERROR("Unknown argument: %s\n", name);
1011         return;
1012     }
1013     val->i = iv;
1014 }
1015
1016 void
1017 cmd_ln_set_float_r(cmd_ln_t *cmdln, char const *name, double fv)
1018 {
1019     anytype_t *val;
1020     val = cmd_ln_access_r(cmdln, name);
1021     if (val == NULL) {
1022         E_ERROR("Unknown argument: %s\n", name);
1023         return;
1024     }
1025     val->fl = fv;
1026 }
1027
1028 cmd_ln_t *
1029 cmd_ln_retain(cmd_ln_t *cmdln)
1030 {
1031     ++cmdln->refcount;
1032     return cmdln;
1033 }
1034
1035 int
1036 cmd_ln_free_r(cmd_ln_t *cmdln)
1037 {
1038     if (cmdln == NULL)
1039         return 0;
1040     if (--cmdln->refcount > 0)
1041         return cmdln->refcount;
1042
1043     if (cmdln->ht) {
1044         glist_t entries;
1045         gnode_t *gn;
1046         int32 n;
1047
1048         entries = hash_table_tolist(cmdln->ht, &n);
1049         for (gn = entries; gn; gn = gnode_next(gn)) {
1050             hash_entry_t *e = gnode_ptr(gn);
1051             cmd_ln_val_free((cmd_ln_val_t *)e->val);
1052         }
1053         glist_free(entries);
1054         hash_table_free(cmdln->ht);
1055         cmdln->ht = NULL;
1056     }
1057
1058     if (cmdln->f_argv) {
1059         int32 i;
1060         for (i = 0; i < cmdln->f_argc; ++i) {
1061             ckd_free(cmdln->f_argv[i]);
1062         }
1063         ckd_free(cmdln->f_argv);
1064         cmdln->f_argv = NULL;
1065         cmdln->f_argc = 0;
1066     }
1067     ckd_free(cmdln);
1068     return 0;
1069 }
1070
1071 void
1072 cmd_ln_free(void)
1073 {
1074     cmd_ln_free_r(global_cmdln);
1075     global_cmdln = NULL;
1076 }