]> mj.ucw.cz Git - libucw.git/blob - lib/conf2.c
implemented a few functions of the new configuration mechanism:
[libucw.git] / lib / conf2.c
1 /*
2  *      UCW Library -- Reading of configuration files
3  *
4  *      (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5  *      (c) 2003--2006 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "lib/lib.h"
12 #include "lib/conf2.h"
13 #include "lib/mempool.h"
14
15 #include <stdlib.h>
16 #include <errno.h>
17
18 /* Memory allocation */
19
20 static struct mempool *cf_pool;
21
22 void *
23 cf_malloc(uns size)
24 {
25   return mp_alloc(cf_pool, size);
26 }
27
28 void *
29 cf_malloc_zero(uns size)
30 {
31   return mp_alloc_zero(cf_pool, size);
32 }
33
34 byte *
35 cf_strdup(byte *s)
36 {
37   return mp_strdup(cf_pool, s);
38 }
39
40 byte *
41 cf_printf(char *fmt, ...)
42 {
43   va_list args;
44   va_start(args, fmt);
45   byte *res = mp_vprintf(cf_pool, fmt, args);
46   va_end(args);
47   return res;
48 }
49
50 /* Undo journal */
51
52 static uns journal_active;
53
54 uns
55 cf_journal_active(uns flag)
56 {
57   uns f = journal_active;
58   journal_active = flag;
59   return f;
60 }
61
62 void
63 cf_journal_block(void *ptr UNUSED, uns len UNUSED)
64 {
65 }
66
67 /* Parsers for standard types */
68
69 struct unit {
70   uns name;                     // one-letter name of the unit
71   uns num, den;                 // fraction
72 };
73
74 static const struct unit units[] = {
75   { 'd', 86400, 1 },
76   { 'h', 3600, 1 },
77   { 'k', 1000, 1 },
78   { 'm', 1000000, 1 },
79   { 'g', 1000000000, 1 },
80   { 'K', 1024, 1 },
81   { 'M', 1048576, 1 },
82   { 'G', 1073741824, 1 },
83   { '%', 1, 100 },
84   { 0, 0, 0 }
85 };
86
87 static const struct unit *
88 lookup_unit(byte *value, byte *end, byte **msg)
89 {
90   if (end && *end) {
91     if (end == value || end[1] || *end >= '0' && *end <= '9')
92       *msg = "Invalid number";
93     else {
94       for (const struct unit *u=units; u->name; u++)
95         if (u->name == *end)
96           return u;
97       *msg = "Invalid unit";
98     }
99   }
100   return NULL;
101 }
102
103 static char cf_rngerr[] = "Number out of range";
104
105 static byte *
106 cf_parse_int(uns number, byte **pars, int *ptr)
107 {
108   cf_journal_block(ptr, number * sizeof(int));
109   for (uns i=0; i<number; i++)
110   {
111     byte *msg = NULL;
112     if (!*pars[i])
113       msg = "Missing number";
114     else {
115       const struct unit *u;
116       char *end;
117       errno = 0;
118       uns x = strtoul(pars[i], &end, 0);
119       if (errno == ERANGE)
120         msg = cf_rngerr;
121       else if (u = lookup_unit(pars[i], end, &msg)) {
122         u64 y = (u64)x * u->num;
123         if (y % u->den)
124           msg = "Number is not an integer";
125         else {
126           y /= u->den;
127           if (y > 0xffffffff)
128             msg = cf_rngerr;
129           ptr[i] = y;
130         }
131       } else
132         ptr[i] = x;
133     }
134     if (msg)
135       return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
136   }
137   return NULL;
138 }
139
140 static byte *
141 cf_parse_u64(uns number, byte **pars, u64 *ptr)
142 {
143   cf_journal_block(ptr, number * sizeof(u64));
144   for (uns i=0; i<number; i++)
145   {
146     byte *msg = NULL;
147     if (!*pars[i])
148       msg = "Missing number";
149     else {
150       const struct unit *u;
151       char *end;
152       errno = 0;
153       u64 x = strtoull(pars[i], &end, 0);
154       if (errno == ERANGE)
155         msg = cf_rngerr;
156       else if (u = lookup_unit(pars[i], end, &msg)) {
157         if (x > ~(u64)0 / u->num)
158           msg = "Number out of range";
159         else {
160           x *= u->num;
161           if (x % u->den)
162             msg = "Number is not an integer";
163           else
164             ptr[i] = x / u->den;
165         }
166       } else
167         ptr[i] = x;
168     }
169     if (msg)
170       return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
171   }
172   return NULL;
173 }
174
175 static byte *
176 cf_parse_double(uns number, byte **pars, double *ptr)
177 {
178   cf_journal_block(ptr, number * sizeof(double));
179   for (uns i=0; i<number; i++)
180   {
181     byte *msg = NULL;
182     if (!*pars[i])
183       msg = "Missing number";
184     else {
185       const struct unit *u;
186       char *end;
187       errno = 0;
188       double x = strtoul(pars[i], &end, 0);
189       if (errno == ERANGE)
190         msg = cf_rngerr;
191       else if (u = lookup_unit(pars[i], end, &msg))
192         ptr[i] = x * u->num / u->den;
193       else
194         ptr[i] = x;
195     }
196     if (msg)
197       return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
198   }
199   return NULL;
200 }
201
202 static byte *
203 cf_parse_string(uns number, byte **pars, byte **ptr)
204 {
205   cf_journal_block(ptr, number * sizeof(byte*));
206   for (uns i=0; i<number; i++)
207     ptr[i] = cf_strdup(pars[i]);
208   return NULL;
209 }
210
211 static byte *
212 cf_parse_int_ary(uns number, byte **pars, int **ptr)
213 {
214   cf_journal_block(ptr, sizeof(int**));
215   *ptr = (int*) cf_malloc((number+1) * sizeof(int*)) + 1;
216   ARRAY_LEN(*ptr) = number;
217   uns old_flag = cf_journal_active(0);
218   byte *msg = cf_parse_int(number, pars, *ptr);
219   cf_journal_active(old_flag);
220   return msg;
221 }
222
223 static byte *
224 cf_parse_u64_ary(uns number, byte **pars, u64 **ptr)
225 {
226   cf_journal_block(ptr, sizeof(u64**));
227   *ptr = (u64*) cf_malloc((number+1) * sizeof(u64*)) + 1;
228   ARRAY_LEN(*ptr) = number;
229   uns old_flag = cf_journal_active(0);
230   byte *msg = cf_parse_u64(number, pars, *ptr);
231   cf_journal_active(old_flag);
232   return msg;
233 }
234
235 static byte *
236 cf_parse_double_ary(uns number, byte **pars, double **ptr)
237 {
238   cf_journal_block(ptr, sizeof(double**));
239   *ptr = (double*) cf_malloc((number+1) * sizeof(double*)) + 1;
240   ARRAY_LEN(*ptr) = number;
241   uns old_flag = cf_journal_active(0);
242   byte *msg = cf_parse_double(number, pars, *ptr);
243   cf_journal_active(old_flag);
244   return msg;
245 }
246
247 static byte *
248 cf_parse_string_ary(uns number, byte **pars, byte ***ptr)
249 {
250   cf_journal_block(ptr, sizeof(byte***));
251   *ptr = (byte**) cf_malloc((number+1) * sizeof(byte**)) + 1;
252   ARRAY_LEN(*ptr) = number;
253   uns old_flag = cf_journal_active(0);
254   byte *msg = cf_parse_string(number, pars, *ptr);
255   cf_journal_active(old_flag);
256   return msg;
257 }