]> mj.ucw.cz Git - libucw.git/blob - lib/shell/config.c
21bf540d0f098b397ef47f3c5fc07561463f9c4b
[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/conf2.h"
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <alloca.h>
26
27 enum flag {
28   F_STRING = 0,
29   F_INT = 1,
30   F_DOUBLE = 2,
31   F_INT64 = 3,
32   F_TYPE_MASK = 7,
33   F_ARRAY = 0x80,
34 };
35
36 static void
37 help(void)
38 {
39   fputs("\n\
40 Usage: config [-C<configfile>] [-S<section>.<option>=<value>] <section> [@]<item><type>[=<default>] <item2> ... [*]\n\
41 \n\
42 Types:\n\
43 <empty>\t\tString\n\
44 #\t\t32-bit integer\n\
45 ##\t\t64-bit integer\n\
46 $\t\tFloating point number\n\
47 \n\
48 Modifiers:\n\
49 @\t\tMultiple occurences of the item are passed as an array (otherwise the last one wins)\n\
50 *\t\tIgnore unknown items instead of reporting them as errors\n\
51 ", stderr);
52   exit(1);
53 }
54
55 static byte *
56 report(uns num, byte **pars, struct cf_item *item)
57 {
58   uns f = item->type;
59   for (uns i=0; i<num; i++)
60   {
61     byte buf[128];
62     byte *err, *value = buf;
63     switch (f & F_TYPE_MASK) {
64       case F_STRING:
65         value = pars[i];
66         break;
67       case F_INT:
68         ; uns val;
69         if (err = cf_parse_int(pars[i], &val))
70           return err;
71         sprintf(buf, "%d", val);
72         break;
73       case F_INT64:
74         ; u64 val64;
75         if (err = cf_parse_u64(pars[i], &val64))
76           return err;
77         sprintf(buf, "%Lu", val64);
78         break;
79       case F_DOUBLE:
80         ; double valf;
81         if (err = cf_parse_double(pars[i], &valf))
82           return err;
83         sprintf(buf, "%g", valf);
84         break;
85       default:
86         ASSERT(0);
87     }
88
89     if (f & F_ARRAY)
90       printf("CF_%s[${#CF_%s[*]}]='", item->name, item->name);
91     else
92       printf("CF_%s='", item->name);
93     while (*value) {
94       if (*value == '\'')
95         die("Apostrophes are not supported in config of scripts");
96       putchar(*value++);
97     }
98     puts("'");
99   }
100   return NULL;
101 }
102
103 int main(int argc, char **argv)
104 {
105   int i = 1;
106   int start;
107
108   log_init("config");
109   while (i < argc && argv[i][0] == '-')
110     i++;
111   if (i + 1 >= argc)
112     help();
113   start = i;
114
115   byte *sec_name = argv[i++];
116   uns allow_unknown = 0;
117   struct cf_section *sec = xmalloc_zero(sizeof(struct cf_section));
118   struct cf_item *c = sec->cfg = xmalloc_zero(sizeof(struct cf_item) * (argc-i+1));
119
120   for (; i<argc; i++)
121     {
122       byte *arg = xstrdup(argv[i]);
123       if (!strcmp(arg, "*"))
124         allow_unknown = 1;
125       else
126         {
127           byte *e = strchr(arg, '=');
128           if (e)
129             *e++ = 0;
130
131           byte *t = arg + strlen(arg) - 1;
132           if (t > arg)
133             {
134               if (*t == '#')
135                 {
136                   *t-- = 0;
137                   if (t > arg && *t == '#')
138                     {
139                       *t-- = 0;
140                       c->type |= F_INT64;
141                     }
142                   else
143                     c->type |= F_INT;
144                 }
145               else if (*t == '$')
146                 {
147                   *t-- = 0;
148                   c->type |= F_DOUBLE;
149                 }
150             }
151
152           if (*arg == '@')
153             {
154               arg++;
155               printf("declare -a CF_%s ; CF_%s=()\n", arg, arg);
156               c->type |= F_ARRAY;
157             }
158
159           c->cls = CC_PARSER;
160           c->name = arg;
161           c->number = (c->type & F_ARRAY) ? CF_ANY_NUM : 1;
162           c->ptr = c;
163           c->u.par = (cf_parser*) report;
164           if (e)
165             report(1, &e, c);
166           c++;
167         }
168     }
169   c->cls = CC_END;
170   cf_declare_section(sec_name, sec, allow_unknown);
171   if (cf_get_opt(start, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
172     help();
173   return 0;
174 }