]> mj.ucw.cz Git - libucw.git/blob - lib/shell/config.c
Merge with git+ssh://cvs.ucw.cz/projects/sherlock/GIT/sherlock.git#dev-config
[libucw.git] / lib / shell / config.c
1 /*
2  *      UCW Library -- Shell Interface to Configuration Files
3  *
4  *      (c) 2002--2005 Martin Mares <mj@ucw.cz>
5  *      (c) 2006 Robert Spalek <robert@ucw.cz>
6  *
7  *      Once we were using this beautiful Shell version, but it turned out
8  *      that it doesn't work with nested config files:
9  *
10  *              eval `sed <cf/sherlock '/^#/d;/^ *$/d;s/ \+$//;
11  *              h;s@[^  ]*@@;x;s@[      ].*@@;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;G;s/\n//;
12  *              /^\[SECTION\]/,/^\[/ {; /^[A-Z]/ { s/^\([^      ]\+\)[  ]*\(.*\)$/SH_\1="\2"/; p; }; };
13  *              d;'`
14  *
15  *      This software may be freely distributed and used according to the terms
16  *      of the GNU Lesser General Public License.
17  */
18
19 #include "lib/lib.h"
20 #include "lib/conf.h"
21 #include "lib/getopt.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <alloca.h>
27
28 enum flag {
29   F_STRING = 0,
30   F_INT = 1,
31   F_DOUBLE = 2,
32   F_INT64 = 3,
33   F_TYPE_MASK = 7,
34   F_ARRAY = 0x80,
35 };
36
37 static void
38 help(void)
39 {
40   fputs("\n\
41 Usage: config [-C<configfile>] [-S<section>.<option>=<value>] <section> [@]<item><type>[=<default>] <item2> ... [*]\n\
42 \n\
43 Types:\n\
44 <empty>\t\tString\n\
45 #\t\t32-bit integer\n\
46 ##\t\t64-bit integer\n\
47 $\t\tFloating point number\n\
48 \n\
49 Modifiers:\n\
50 @\t\tMultiple occurences of the item are passed as an array (otherwise the last one wins)\n\
51 *\t\tIgnore unknown items instead of reporting them as errors\n\
52 ", stderr);
53   exit(1);
54 }
55
56 static byte *
57 report(uns num, byte **pars, struct cf_item *item)
58 {
59   uns f = item->type;
60   for (uns i=0; i<num; i++)
61   {
62     byte buf[128];
63     byte *err, *value = buf;
64     switch (f & F_TYPE_MASK) {
65       case F_STRING:
66         value = pars[i];
67         break;
68       case F_INT:
69         ; uns val;
70         if (err = cf_parse_int(pars[i], &val))
71           return err;
72         sprintf(buf, "%d", val);
73         break;
74       case F_INT64:
75         ; u64 val64;
76         if (err = cf_parse_u64(pars[i], &val64))
77           return err;
78         sprintf(buf, "%Lu", val64);
79         break;
80       case F_DOUBLE:
81         ; double valf;
82         if (err = cf_parse_double(pars[i], &valf))
83           return err;
84         sprintf(buf, "%g", valf);
85         break;
86       default:
87         ASSERT(0);
88     }
89
90     if (f & F_ARRAY)
91       printf("CF_%s[${#CF_%s[*]}]='", item->name, item->name);
92     else
93       printf("CF_%s='", item->name);
94     while (*value) {
95       if (*value == '\'')
96         die("Apostrophes are not supported in config of scripts");
97       putchar(*value++);
98     }
99     puts("'");
100   }
101   return NULL;
102 }
103
104 int main(int argc, char **argv)
105 {
106   int i = 1;
107   int start;
108
109   log_init("config");
110   while (i < argc && argv[i][0] == '-')
111     i++;
112   if (i + 1 >= argc)
113     help();
114   start = i;
115
116   byte *sec_name = argv[i++];
117   uns allow_unknown = 0;
118   struct cf_section *sec = xmalloc_zero(sizeof(struct cf_section));
119   struct cf_item *c = sec->cfg = xmalloc_zero(sizeof(struct cf_item) * (argc-i+1));
120
121   for (; i<argc; i++)
122     {
123       byte *arg = xstrdup(argv[i]);
124       if (!strcmp(arg, "*"))
125         allow_unknown = 1;
126       else
127         {
128           byte *e = strchr(arg, '=');
129           if (e)
130             *e++ = 0;
131
132           byte *t = arg + strlen(arg) - 1;
133           if (t > arg)
134             {
135               if (*t == '#')
136                 {
137                   *t-- = 0;
138                   if (t > arg && *t == '#')
139                     {
140                       *t-- = 0;
141                       c->type |= F_INT64;
142                     }
143                   else
144                     c->type |= F_INT;
145                 }
146               else if (*t == '$')
147                 {
148                   *t-- = 0;
149                   c->type |= F_DOUBLE;
150                 }
151             }
152
153           if (*arg == '@')
154             {
155               arg++;
156               printf("declare -a CF_%s ; CF_%s=()\n", arg, arg);
157               c->type |= F_ARRAY;
158             }
159
160           c->cls = CC_PARSER;
161           c->name = arg;
162           c->number = (c->type & F_ARRAY) ? CF_ANY_NUM : 1;
163           c->ptr = c;
164           c->u.par = (cf_parser*) report;
165           if (e) {
166             byte *err = report(1, &e, c);
167             if (err)
168               die("Cannot parse the default value #%d: %s", c-sec->cfg, err);
169           }
170           c++;
171         }
172     }
173   c->cls = CC_END;
174   cf_declare_section(sec_name, sec, allow_unknown);
175   if (cf_getopt(start, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
176     help();
177   return 0;
178 }