Bump versions.
[gnutls.git] / src / cfg / shared.c
blob1219f4705990a1f1a53414b65572a6eb13104986
1 /*
2 * libcfg+ - precise command line & config file parsing library
4 * shared.c - shared stuff for command line and config file
5 * ____________________________________________________________
7 * Developed by Ondrej Jombik <nepto@platon.sk>
8 * and Lubomir Host <rajo@platon.sk>
9 * Copyright (c) 2001-2004 Platon SDG, http://platon.sk/
10 * All rights reserved.
12 * See README file for more information about this software.
13 * See COPYING file for license information.
15 * Download the latest version from
16 * http://platon.sk/projects/libcfg+/
19 /* $Platon: libcfg+/src/shared.c,v 1.36 2004/01/12 06:03:09 nepto Exp $ */
21 /* Includes {{{ */
22 #ifdef HAVE_CONFIG_H
23 # include <config.h>
24 #endif
26 #if STDC_HEADERS
27 # include <stdlib.h>
28 #else
29 # if HAVE_STDLIB_H
30 # include <stdlib.h>
31 # endif
32 #endif
33 #if HAVE_STRING_H
34 # if !STDC_HEADERS && HAVE_MEMORY_H
35 # include <memory.h>
36 # endif
37 # include <string.h>
38 #endif
39 #if HAVE_STRINGS_H
40 # include <strings.h>
41 #endif
42 #if HAVE_MATH_H
43 # include <math.h>
44 #endif
45 #if HAVE_LIMITS_H
46 # include <limits.h>
47 #endif
48 #if HAVE_FLOAT_H
49 # include <float.h>
50 #endif
51 #if HAVE_CTYPE_H
52 # include <ctype.h>
53 #endif
54 #if HAVE_ERRNO_H
55 # include <errno.h>
56 #endif
58 #include <platon/str/strplus.h>
59 #include <platon/str/strdyn.h>
61 #include "cfg+.h"
62 /* }}} */
64 /* Static function declarations {{{ */
65 static int search_cur_opt_idx(const CFG_CONTEXT con);
66 static int add_to_used_opt_idx(const CFG_CONTEXT con, int opt_idx);
67 static int store_multi_arg(
68 const int type,
69 const char **multi_arg,
70 void ***ar);
71 static int store_single_arg(
72 const int type,
73 const char *arg,
74 const void *where);
75 static int split_multi_arg(
76 char *arg,
77 char ***ar,
78 char **quote_prefix_ar,
79 char **quote_postfix_ar,
80 char **separator_ar);
81 static int unquote_single_arg(
82 char *arg,
83 char **quote_prefix_ar,
84 char **quote_postfix_ar);
85 /* }}} */
88 * EXTERN PLATON_FUNCS
91 void
92 __cfg_free_currents(con)
93 const CFG_CONTEXT con;
94 { /* {{{ */
95 if (con->cur_opt != NULL)
96 free(con->cur_opt);
97 if (con->cur_arg != NULL)
98 free(con->cur_arg);
100 con->cur_opt = con->cur_arg = NULL;
101 con->cur_opt_type = CFG_NONE_OPTION;
102 } /* }}} */
105 __cfg_process_currents(con, ret_val, arg_used)
106 const CFG_CONTEXT con;
107 int *ret_val;
108 int *arg_used;
109 { /* {{{ */
110 register int ret = 0;
111 register int opt_idx;
112 register int opt_type, opt_data_type, opt_f_multi, opt_f_multi_sep;
113 register char **quote_prefix_ar, **quote_postfix_ar, **separator_ar;
115 *ret_val = 0;
116 if (arg_used != NULL)
117 *arg_used = 0;
119 opt_idx = search_cur_opt_idx(con);
121 #if defined(DEBUG) && DEBUG
122 fprintf(stderr, "%s|%ld|%s|%s|%s|%d|flags=%x[",
123 con->type == CFG_LINE ? "cmdline" : "cfgfile",
124 con->type == CFG_LINE ? con->cur_idx : 0,
125 con->type == CFG_LINE ? con->argv[con->cur_idx] : "N/A",
126 con->cur_opt == NULL ? "[NULL]" : con->cur_opt,
127 con->cur_arg == NULL ? "[NULL]" : con->cur_arg,
128 opt_idx, con->cur_opt_type);
130 if (con->cur_opt_type & CFG_LONG_OPTION)
131 fputs("-LONG-", stderr);
132 if (con->cur_opt_type & CFG_SHORT_OPTION)
133 fputs("-SHORT-", stderr);
134 if (con->cur_opt_type & CFG_SHORT_OPTIONS)
135 fputs("-SHORTS-", stderr);
136 if (con->cur_opt_type & CFG_LONG_SEPINIT)
137 fputs("-SEPINIT-", stderr);
139 fputs("]\n", stderr);
140 #endif
142 if (opt_idx < 0)
143 return CFG_ERROR_UNKNOWN; /* unknown option reached */
145 if (! (con->flags & CFG_IGNORE_MULTI)
146 && ! (con->options[opt_idx].type & CFG_MULTI)) {
147 ret = add_to_used_opt_idx(con, opt_idx);
149 if (ret < 0)
150 return CFG_ERROR_NOMEM;
151 else if (ret > 0)
152 return CFG_ERROR_MULTI;
155 /* Setting others opt_XXX constants according to *opt_idx. */
156 /* opt_data_type - option data type, opt_f_XXX - option flags */
157 opt_type = con->options[opt_idx].type;
158 opt_data_type = opt_type & CFG_DATA_TYPE_MASK;
159 opt_f_multi = opt_type & CFG_MULTI;
160 opt_f_multi_sep = opt_type & (CFG_MULTI_SEPARATED & ~CFG_MULTI);
162 if (con->type == CFG_LINE) {
163 quote_prefix_ar = con->prop[CFG_LINE_QUOTE_PREFIX];
164 quote_postfix_ar = con->prop[CFG_LINE_QUOTE_POSTFIX];
165 separator_ar = (opt_type & CFG_LEFTOVER_ARGS)
166 ? con->prop[CFG_LINE_LEFTOVER_MULTI_VALS_SEPARATOR]
167 : con->prop[CFG_LINE_NORMAL_MULTI_VALS_SEPARATOR];
169 else {
170 quote_prefix_ar = con->prop[CFG_FILE_QUOTE_PREFIX];
171 quote_postfix_ar = con->prop[CFG_FILE_QUOTE_POSTFIX];
172 separator_ar = (opt_type & CFG_LEFTOVER_ARGS)
173 ? con->prop[CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR]
174 : con->prop[CFG_FILE_NORMAL_MULTI_VALS_SEPARATOR];
177 switch (opt_data_type) {
178 default:
179 return CFG_ERROR_INTERNAL;
180 break;
182 /* Boolean data type */
184 case CFG_BOOLEAN:
185 if (con->cur_opt_type & CFG_LONG_SEPINIT
186 && con->cur_arg != NULL)
187 return CFG_ERROR_NOTALLOWEDARG;
189 if (con->options[opt_idx].value != NULL)
190 (*((int *) con->options[opt_idx].value))++;
191 break;
193 /* Numeric (int, long, float and double) data types */
195 case CFG_INT:
196 case CFG_UINT:
197 case CFG_LONG:
198 case CFG_ULONG:
199 case CFG_FLOAT:
200 case CFG_DOUBLE:
202 if (con->cur_arg == NULL)
203 return CFG_ERROR_NOARG;
205 if (opt_f_multi) {
206 char **add;
207 char *static_add[2] = {NULL, NULL};
209 if (opt_f_multi_sep) {
211 ret = split_multi_arg(con->cur_arg, &add,
212 quote_prefix_ar, quote_postfix_ar, separator_ar);
214 if (ret != CFG_OK) {
215 PLATON_FUNC(strdyn_safe_free)(add);
216 return ret;
219 else {
220 add = static_add;
221 add[0] = con->cur_arg;
224 ret = store_multi_arg(opt_data_type,
225 (const char **) add,
226 con->options[opt_idx].value);
228 if (add != static_add)
229 PLATON_FUNC(strdyn_free)((char **) add);
231 else {
232 ret = unquote_single_arg(con->cur_arg,
233 quote_prefix_ar, quote_postfix_ar);
235 if (ret != CFG_OK)
236 return ret;
238 ret = store_single_arg(opt_data_type, con->cur_arg,
239 con->options[opt_idx].value);
242 if (ret != CFG_OK)
243 return ret;
245 if (arg_used != NULL)
246 *arg_used = 1;
247 break;
249 /* String data type */
251 case CFG_STRING:
253 if (con->cur_arg == NULL)
254 return CFG_ERROR_NOARG;
256 if (con->options[opt_idx].value != NULL) {
257 if (opt_f_multi) {
258 register char ***p;
259 p = (char ***) con->options[opt_idx].value;
261 if (opt_f_multi_sep) {
262 char **ar;
263 ret = split_multi_arg(con->cur_arg, &ar,
264 quote_prefix_ar, quote_postfix_ar,
265 separator_ar);
267 if (ret != CFG_OK) {
268 PLATON_FUNC(strdyn_safe_free)(ar);
269 return ret;
272 if ((*p = PLATON_FUNC(strdyn_add_ar)(*p, ar)) == NULL)
273 return CFG_ERROR_NOMEM;
275 PLATON_FUNC(strdyn_free)(ar);
277 else {
278 ret = unquote_single_arg(con->cur_arg,
279 quote_prefix_ar, quote_postfix_ar);
281 if (ret != CFG_OK)
282 return ret;
284 if ((*p = PLATON_FUNC(strdyn_add)(*p, con->cur_arg)) == NULL)
285 return CFG_ERROR_NOMEM;
288 else {
289 ret = unquote_single_arg(con->cur_arg,
290 quote_prefix_ar, quote_postfix_ar);
292 if (ret != CFG_OK)
293 return ret;
295 *((char **) con->options[opt_idx].value) =
296 strdup(con->cur_arg);
300 if (arg_used != NULL)
301 *arg_used = 1;
302 break;
305 *ret_val = con->options[opt_idx].val;
307 return CFG_OK;
308 } /* }}} */
311 __cfg_cmdline_set_currents(con)
312 const CFG_CONTEXT con;
313 { /* {{{ */
314 register int i, size;
315 register char *s, *s_sep, *s_tmp;
316 register char *ptr;
318 size = -1; /* size of matched prefix (0 is also valid) */
319 s = con->argv[con->cur_idx]; /* string to scan */
321 /* Explicit `size_t' to `int' typecastings are required here near strlen()
322 calls, else strlen("") == 0 will be considered as smaller than -1. */
324 for (i = 0; (ptr = con->prop[CFG_LINE_SHORT_OPTION_PREFIX][i]) != NULL; i++)
325 if ((int) strlen(ptr) > size && strstr(s, ptr) == s) {
326 size = strlen(ptr);
327 con->cur_opt_type = CFG_SHORT_OPTION;
330 for (i = 0; (ptr = con->prop[CFG_LINE_LONG_OPTION_PREFIX][i]) != NULL; i++)
331 if ((int) strlen(ptr) > size && strstr(s, ptr) == s) {
332 size = strlen(ptr);
333 con->cur_opt_type = CFG_LONG_OPTION;
336 s_sep = NULL;
338 switch (con->cur_opt_type) {
339 default:
340 case CFG_NONE_OPTION: /* None option prefix */
341 break;
343 case CFG_SHORT_OPTION: /* Short option prefix */
344 s += size;
345 s_sep = strlen(s) > 0 ? s + 1 : s;
347 if (strlen(s_sep) > 0) {
348 con->cur_opt_type += CFG_SHORT_OPTIONS;
350 if ((con->cur_arg = strdup(s_sep)) == NULL)
351 return CFG_ERROR_NOMEM;
353 else {
354 if (con->argv[con->cur_idx + 1] != NULL) {
355 con->cur_arg = strdup(con->argv[con->cur_idx + 1]);
356 if (con->cur_arg == NULL)
357 return CFG_ERROR_NOMEM;
359 else
360 con->cur_arg = NULL;
362 break;
364 case CFG_LONG_OPTION: /* Long option prefix */
365 s += size;
366 size = 0;
368 for (i = 0; (ptr = con->prop[CFG_LINE_OPTION_ARG_SEPARATOR][i])
369 != NULL; i++)
370 if ((s_tmp = strstr(s, ptr)) != NULL)
371 if (s_sep == NULL || s_tmp < s_sep
372 || (s_tmp == s_sep && strlen(ptr) > size)) {
373 s_sep = s_tmp;
374 size = strlen(ptr);
377 if (s_sep == NULL) {
378 if (con->argv[con->cur_idx + 1] != NULL) {
379 con->cur_arg = strdup(con->argv[con->cur_idx + 1]);
380 if (con->cur_arg == NULL)
381 return CFG_ERROR_NOMEM;
383 else
384 con->cur_arg = NULL;
386 else {
387 con->cur_opt_type += CFG_LONG_SEPINIT;
388 if ((con->cur_arg = strdup(s_sep + size)) == NULL)
389 return CFG_ERROR_NOMEM;
393 if (s_sep == NULL)
394 s_sep = s + strlen(s);
396 con->cur_opt = (char *) malloc((s_sep - s + 1) * sizeof(char));
397 if (con->cur_opt == NULL)
398 return CFG_ERROR_NOMEM;
400 strncpy(con->cur_opt, s, s_sep - s);
401 con->cur_opt[s_sep - s] = '\0';
403 if (con->cur_opt_type == CFG_NONE_OPTION) {
404 register char *tmp_str;
405 tmp_str = con->cur_opt;
406 con->cur_opt = con->cur_arg;
407 con->cur_arg = tmp_str;
410 return CFG_OK;
411 } /* }}} */
414 __cfg_cfgfile_set_currents(con, buf)
415 const CFG_CONTEXT con;
416 char *buf;
417 { /* {{{ */
418 register char **pos;
419 register char *s_sep, *s_tmp;
420 register int size;
422 s_sep = NULL;
423 size = 0;
424 for (pos = con->prop[CFG_FILE_OPTION_ARG_SEPARATOR];
425 pos != NULL && *pos != NULL; pos++) {
427 if ((s_tmp = strstr(buf, *pos)) != NULL)
428 if (s_sep == NULL || s_tmp < s_sep
429 || (s_tmp == s_sep && strlen(*pos) > size)) {
430 s_sep = s_tmp;
431 size = strlen(*pos);
435 if (s_sep == NULL) {
436 con->cur_arg = NULL;
438 con->cur_opt = strdup(buf);
439 if (con->cur_opt == NULL)
440 return CFG_ERROR_NOMEM;
442 else {
443 con->cur_opt = (char *) malloc((s_sep - buf + 1) * sizeof(char));
444 if (con->cur_opt == NULL)
445 return CFG_ERROR_NOMEM;
447 strncpy(con->cur_opt, buf, s_sep - buf);
448 con->cur_opt[s_sep - buf] = '\0';
450 if ((con->cur_arg = strdup(s_sep + size)) == NULL)
451 return CFG_ERROR_NOMEM;
453 PLATON_FUNC(str_right_trim)(con->cur_opt);
454 PLATON_FUNC(str_left_trim)(con->cur_arg);
457 return CFG_OK;
458 } /* }}} */
461 * STATIC PLATON_FUNCS
465 * search_cur_opt_idx()
467 * Function searches con->options for con->cur_opt.
468 * Returns index on success or -1 if not found.
471 static int
472 search_cur_opt_idx(con)
473 const CFG_CONTEXT con;
474 { /* {{{ */
475 register int i;
477 for (i = 0; con->options[i].cmdline_long_name != NULL
478 || con->options[i].cmdline_short_name != '\0'
479 || con->options[i].cfgfile_name != NULL
480 || con->options[i].type != CFG_END
481 || con->options[i].value != NULL
482 || con->options[i].val != 0;
483 i++)
485 if (con->type == CFG_CMDLINE) { /* Command line context type */
486 if ((con->cur_opt_type & CFG_LONG_OPTION && con->cur_opt != NULL
487 && con->options[i].cmdline_long_name != NULL
488 && ! strcmp(con->cur_opt,
489 con->options[i].cmdline_long_name))
490 || (con->cur_opt_type & CFG_SHORT_OPTION &&
491 con->cur_opt[0] != '\0' && /* to prevent '-' option */
492 con->cur_opt[0] == con->options[i].cmdline_short_name)
493 || (con->cur_opt_type == CFG_NONE_OPTION &&
494 con->options[i].type & CFG_LEFTOVER_ARGS))
496 return i;
498 else { /* Configuration file context type */
499 int len;
501 if (con->cur_opt != NULL
502 && con->options[i].cfgfile_name != NULL
503 && con->cur_opt == PLATON_FUNC(str_white_str)(con->cur_opt,
504 (char *)(con->options[i].cfgfile_name), &len)
505 && len == strlen(con->cur_opt))
507 return i;
511 return -1;
512 } /* }}} */
516 * Size of realloc() step for used_opt member of cfg_context structure.
517 * Value must be grater than 0.
520 #ifdef CFG_USED_OPT_IDX_STEP
521 # undef CFG_USED_OPT_IDX_STEP
522 #endif
524 #if defined(DEBUG) && DEBUG
525 # define CFG_USED_OPT_IDX_STEP (1)
526 #else
527 # define CFG_USED_OPT_IDX_STEP (10)
528 #endif
531 * add_to_used_opt_idx()
533 * Function adds opt_idx to dynamic array con->used_opt_idx. If array is full,
534 * it is realloc()-ed according to CFG_USED_OPT_IDX_STEP constant. Array
535 * used_opt_idx is primary used for detecting multiple options on command line.
537 * Note, that in array -1 means empty cell, which can be overwritten by option
538 * index value and -255 means end of array. If there is no -1 left in array,
539 * array must be resized to add new option index value.
541 * Retuns -1 on not enough memory error, 1 if opt_idx founded in array and 0 if
542 * opt_idx was sucessfully added to array.
545 static int
546 add_to_used_opt_idx(con, opt_idx)
547 const CFG_CONTEXT con;
548 int opt_idx;
549 { /* {{{ */
550 int *p_i = NULL;
552 if (opt_idx < 0)
553 return 1;
555 if (con->used_opt_idx != NULL)
556 for (p_i = con->used_opt_idx; *p_i >= 0; p_i++)
557 if (*p_i == opt_idx)
558 return 1;
560 if (p_i == NULL || *p_i == -255) {
561 register int *p_j;
562 register int new_size;
564 new_size = (p_i == NULL ? 0 : p_i - con->used_opt_idx)
565 + 1 + CFG_USED_OPT_IDX_STEP;
567 con->used_opt_idx = (int *) realloc(con->used_opt_idx,
568 new_size * sizeof(int));
570 #if defined(DEBUG) && DEBUG
571 printf("add_to_used_opt_idx(con, %d): realloc(%d) = %p\n",
572 opt_idx, new_size, (void *) con->used_opt_idx);
573 #endif
575 if (con->used_opt_idx == NULL)
576 return -1;
578 if (p_i == NULL)
579 p_i = con->used_opt_idx;
580 else /* Searching for new p_i after realloc(). */
581 for (p_i = con->used_opt_idx; *p_i >= 0; p_i++) ;
583 for (p_j = p_i; p_j - p_i < CFG_USED_OPT_IDX_STEP; p_j++)
584 *p_j = -1;
586 *p_j = -255;
589 *p_i = opt_idx;
591 return 0;
592 } /* }}} */
595 * store_multi_arg()
597 * According to option date type (type) parses and stores multiple arguments
598 * (multi_arg) by adding to *ar dynamic array. Array resizing is done as first
599 * and than is store_single_arg() function called with appropriate parameters.
602 static int
603 store_multi_arg(type, multi_arg, ar)
604 const int type;
605 const char **multi_arg;
606 void ***ar;
607 { /* {{{ */
608 register int ptr_len, item_len;
609 register int size_plus, size;
610 register int k, ret;
612 switch (type) {
613 default:
614 return CFG_ERROR_INTERNAL;
615 break;
617 case CFG_INT:
618 ptr_len = sizeof(int *);
619 item_len = sizeof(int);
620 break;
622 case CFG_UINT:
623 ptr_len = sizeof(unsigned int *);
624 item_len = sizeof(unsigned int);
625 break;
627 case CFG_LONG:
628 ptr_len = sizeof(long *);
629 item_len = sizeof(long);
630 break;
632 case CFG_ULONG:
633 ptr_len = sizeof(unsigned long *);
634 item_len = sizeof(unsigned long);
635 break;
637 case CFG_FLOAT:
638 ptr_len = sizeof(float *);
639 item_len = sizeof(float);
640 break;
642 case CFG_DOUBLE:
643 ptr_len = sizeof(double *);
644 item_len = sizeof(double);
645 break;
648 for (size_plus = 0; multi_arg[size_plus] != NULL; size_plus++) ;
649 for (size = 0; *ar != NULL && (*ar)[size] != NULL; size++) ;
651 *ar = realloc(*ar, (size + 1 + size_plus) * ptr_len);
653 if (*ar == NULL)
654 return CFG_ERROR_NOMEM;
656 /* Array terminated NULL pointer (end of array). */
657 (*ar)[size + size_plus] = NULL;
659 for (k = 0; k < size_plus; k++) {
660 (*ar)[size + k] = malloc(item_len);
661 if ((*ar)[size + k] == NULL)
662 return CFG_ERROR_NOMEM;
664 ret = store_single_arg(type, multi_arg[k], (*ar)[size + k]);
666 if (ret != CFG_OK) {
667 /* To prevent having random value at size + k position in *ar. */
668 (*ar)[size + k] = NULL;
669 return ret;
673 return CFG_OK;
674 } /* }}} */
677 * store_single_arg()
679 * According to option date type (type) parses and stores single argument (arg)
680 * to specified place pointed by where.
683 static int
684 store_single_arg(type, arg, where)
685 const int type;
686 const char *arg;
687 const void *where;
688 { /* {{{ */
689 register long long_val = 0;
690 register unsigned long ulong_val = 0;
691 register double double_val = 0.0;
692 register int f_integer = 0; /* Searching for integer value? */
693 char *end;
695 if (where == NULL)
696 return CFG_OK;
698 /* Conveting to numeric value. */
699 switch (type) {
700 default:
701 return CFG_ERROR_INTERNAL;
702 break;
704 case CFG_INT:
705 case CFG_UINT:
706 case CFG_LONG:
707 case CFG_ULONG:
708 f_integer = 1;
709 if (type == CFG_ULONG) {
710 ulong_val = strtoul(arg, &end, 0);
711 } else {
712 long_val = strtol(arg, &end, 0);
714 if (! (end == NULL || *end != '\0'))
715 /* Decimal number conversion succeed */
716 break;
718 /* If conversion for integer number failed, we are going to try
719 further integer number initialization in float-like style. */
721 case CFG_FLOAT:
722 case CFG_DOUBLE:
723 double_val = strtod(arg, &end);
724 if (*end)
725 return CFG_ERROR_BADNUMBER;
727 if (double_val == +HUGE_VAL || double_val == -HUGE_VAL)
728 /* Purpously always return overflow error */
729 return f_integer ? CFG_ERROR_OVERFLOW : CFG_ERROR_OVERFLOW;
730 #if HAVE_ERRNO_H
731 if (double_val == 0.0 && errno == ERANGE)
732 #else
733 if (double_val == 0.0 && end == arg)
734 #endif
735 /* Again always return overflow error */
736 return f_integer ? CFG_ERROR_OVERFLOW : CFG_ERROR_OVERFLOW;
738 /* Validating coversion results */
739 if (end == NULL || *end != '\0')
740 return CFG_ERROR_BADNUMBER;
742 if (! f_integer)
743 break;
745 if (type == CFG_ULONG) {
746 register double diff;
747 ulong_val = (unsigned long) double_val;
748 diff = double_val - (double) long_val;
749 if (diff >= 1.0 || diff <= -1.0)
750 return CFG_ERROR_OVERFLOW;
751 if (diff != 0.0)
752 return CFG_ERROR_BADNUMBER;
753 } else {
754 register double diff;
755 long_val = (long) double_val;
756 diff = double_val - (double) long_val;
757 if (diff >= 1.0 || diff <= -1.0)
758 return CFG_ERROR_OVERFLOW;
759 if (diff != 0.0)
760 return CFG_ERROR_BADNUMBER;
762 break;
765 /* Range checking and value storing. */
766 switch (type) {
767 default:
768 return CFG_ERROR_INTERNAL;
769 break;
771 case CFG_INT:
772 if (long_val >= INT_MAX || long_val <= INT_MIN)
773 return CFG_ERROR_OVERFLOW;
775 *((int *) where) = (int) long_val;
776 break;
778 case CFG_UINT:
779 if (long_val > UINT_MAX || long_val < 0)
780 return CFG_ERROR_OVERFLOW;
782 *((unsigned int *) where) = (unsigned int) long_val;
783 break;
785 case CFG_LONG:
786 if (long_val == LONG_MIN || long_val == LONG_MAX)
787 return CFG_ERROR_OVERFLOW;
789 *((long *) where) = long_val;
790 break;
792 case CFG_ULONG:
793 /* Fix strange strtoul() behaviour. */
794 for (end = (char *) arg; isspace(*end); end++) ;
796 /* Testing errno after strtoul() is not needed here. */
797 if (*end == '-' || ulong_val == ULONG_MAX /* || ulong_val == 0 */)
798 return CFG_ERROR_OVERFLOW;
800 *((unsigned long *) where) = (unsigned long) ulong_val;
801 break;
803 case CFG_FLOAT:
804 #ifdef ABS /* Borrowed from popt library. */
805 # undef ABS
806 #endif
807 #define ABS(a) (((a) < 0) ? -(a) : (a))
809 if (double_val != 0.0)
810 if (ABS(double_val) > FLT_MAX || ABS(double_val) < FLT_MIN)
811 return CFG_ERROR_OVERFLOW;
813 *((float *) where) = (float) double_val;
814 break;
816 case CFG_DOUBLE:
817 *((double *) where) = (double) double_val;
818 break;
821 return CFG_OK;
822 } /* }}} */
825 * split_multi_arg()
827 * Splits multi argument with separators with focusing on quotations.
828 * Returns cfg_error type and in ar is result array stored.
831 static int
832 split_multi_arg(arg, ar, quote_prefix_ar, quote_postfix_ar, separator_ar)
833 char *arg;
834 char ***ar;
835 char **quote_prefix_ar;
836 char **quote_postfix_ar;
837 char **separator_ar;
838 { /* {{{ */
839 register int i;
840 int sep_ar_idx, quote_idx, sep_size, tmp_sep_size;
841 char *p_quote, *p_sep, *tmp_s;
842 char *arg_base = arg;
844 if ((*ar = PLATON_FUNC(strdyn_create)()) == NULL)
845 return CFG_ERROR_NOMEM;
847 do {
849 /* Searching first quotation string (p_quote)
850 and set quotation variables */
851 p_quote = PLATON_FUNC(strdyn_str2)(arg, quote_prefix_ar, &quote_idx);
852 p_sep = NULL; /* pointer to separator */
853 sep_ar_idx = -1; /* index of separator */
854 sep_size = 0; /* length of separator string */
856 /* Searching first separator string (p_sep) */
857 for (i = 0; separator_ar[i] != NULL; i++) {
858 if ((tmp_s = PLATON_FUNC(str_white_str)(arg, separator_ar[i], &tmp_sep_size))
859 != NULL && (p_sep == NULL || tmp_s < p_sep)) {
860 p_sep = tmp_s;
861 sep_ar_idx = i;
862 sep_size = tmp_sep_size;
866 /* Process quotation
867 if is is on lower position than separator */
868 if ((p_quote != NULL && p_sep == NULL)
869 || (p_quote != NULL && p_sep != NULL && p_quote < p_sep)) {
871 register char *end_ptr, *prefix, *postfix;
872 register int prefix_len, postfix_len;
874 if (quote_idx < 0 /* not optimized */
875 || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_prefix_ar) - 1
876 || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_postfix_ar) - 1
877 || (prefix = quote_prefix_ar[quote_idx]) == NULL
878 || (postfix = quote_postfix_ar[quote_idx]) == NULL)
879 return CFG_ERROR_INTERNAL;
881 prefix_len = strlen(prefix);
882 postfix_len = strlen(postfix);
884 memmove(p_quote, p_quote + prefix_len,
885 strlen(p_quote + prefix_len) + 1);
887 end_ptr = strstr(p_quote, postfix);
889 if (end_ptr == NULL)
890 return CFG_ERROR_BADQUOTE;
892 memmove(end_ptr, end_ptr + postfix_len,
893 strlen(end_ptr + postfix_len) + 1);
895 arg = end_ptr;
897 /* Separator processing otherwise */
898 else if ((p_sep != NULL && p_quote == NULL)
899 || (p_sep != NULL && p_quote != NULL && p_sep <= p_quote)) {
901 register char c;
903 c = *p_sep;
904 *p_sep = '\0';
905 *ar = PLATON_FUNC(strdyn_add_va)(*ar, arg_base, NULL);
906 *p_sep = c;
907 arg = arg_base = p_sep + sep_size;
909 if (*ar == NULL)
910 return CFG_ERROR_NOMEM;
913 } while (p_quote != NULL || p_sep != NULL);
915 if ((*ar = PLATON_FUNC(strdyn_add_va)(*ar, arg_base, NULL)) == NULL)
916 return CFG_ERROR_NOMEM;
918 return CFG_OK;
919 } /* }}} */
922 * unquote_single_arg()
924 * Unquotes signle argument passed by reference as arg parameter.
925 * Returns cfg_error type and modyfies arg parameter.
928 static int
929 unquote_single_arg(arg, quote_prefix_ar, quote_postfix_ar)
930 char *arg;
931 char **quote_prefix_ar;
932 char **quote_postfix_ar;
933 { /* {{{ */
934 register char *p_quote;
935 int quote_idx;
937 do {
938 p_quote = PLATON_FUNC(strdyn_str2)(arg, quote_prefix_ar, &quote_idx);
940 /* If beginning of quotation was found */
941 if (p_quote != NULL) {
942 register char *end_ptr, *prefix, *postfix;
943 register int prefix_len, postfix_len;
945 if (quote_idx < 0 /* not optimized */
946 || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_prefix_ar) - 1
947 || quote_idx > PLATON_FUNC(strdyn_get_size)(quote_postfix_ar) - 1
948 || (prefix = quote_prefix_ar[quote_idx]) == NULL
949 || (postfix = quote_postfix_ar[quote_idx]) == NULL)
950 return CFG_ERROR_INTERNAL;
952 prefix_len = strlen(prefix);
953 postfix_len = strlen(postfix);
955 memmove(p_quote, p_quote + prefix_len,
956 strlen(p_quote + prefix_len) + 1);
958 end_ptr = strstr(p_quote, postfix);
960 if (end_ptr == NULL)
961 return CFG_ERROR_BADQUOTE;
963 memmove(end_ptr, end_ptr + postfix_len,
964 strlen(end_ptr + postfix_len) + 1);
966 arg = end_ptr;
968 } while (p_quote != NULL);
970 return CFG_OK;
971 } /* }}} */
973 /* Modeline for ViM {{{
974 * vim:set ts=4:
975 * vim600:fdm=marker fdl=0 fdc=0:
976 * }}} */