]> mj.ucw.cz Git - libucw.git/blob - lib/conf2.c
parsers of basic types exported and got rid of the journaling switch
[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 void
53 cf_journal_block(void *ptr UNUSED, uns len UNUSED)
54 {
55 }
56
57 /* Parsers for standard types */
58
59 struct unit {
60   uns name;                     // one-letter name of the unit
61   uns num, den;                 // fraction
62 };
63
64 static const struct unit units[] = {
65   { 'd', 86400, 1 },
66   { 'h', 3600, 1 },
67   { 'k', 1000, 1 },
68   { 'm', 1000000, 1 },
69   { 'g', 1000000000, 1 },
70   { 'K', 1024, 1 },
71   { 'M', 1048576, 1 },
72   { 'G', 1073741824, 1 },
73   { '%', 1, 100 },
74   { 0, 0, 0 }
75 };
76
77 static const struct unit *
78 lookup_unit(byte *value, byte *end, byte **msg)
79 {
80   if (end && *end) {
81     if (end == value || end[1] || *end >= '0' && *end <= '9')
82       *msg = "Invalid number";
83     else {
84       for (const struct unit *u=units; u->name; u++)
85         if (u->name == *end)
86           return u;
87       *msg = "Invalid unit";
88     }
89   }
90   return NULL;
91 }
92
93 static char cf_rngerr[] = "Number out of range";
94
95 byte *
96 cf_parse_int(uns number, byte **pars, int *ptr)
97 {
98   for (uns i=0; i<number; i++)
99   {
100     byte *msg = NULL;
101     if (!*pars[i])
102       msg = "Missing number";
103     else {
104       const struct unit *u;
105       char *end;
106       errno = 0;
107       uns x = strtoul(pars[i], &end, 0);
108       if (errno == ERANGE)
109         msg = cf_rngerr;
110       else if (u = lookup_unit(pars[i], end, &msg)) {
111         u64 y = (u64)x * u->num;
112         if (y % u->den)
113           msg = "Number is not an integer";
114         else {
115           y /= u->den;
116           if (y > 0xffffffff)
117             msg = cf_rngerr;
118           ptr[i] = y;
119         }
120       } else
121         ptr[i] = x;
122     }
123     if (msg)
124       return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
125   }
126   return NULL;
127 }
128
129 byte *
130 cf_parse_u64(uns number, byte **pars, u64 *ptr)
131 {
132   for (uns i=0; i<number; i++)
133   {
134     byte *msg = NULL;
135     if (!*pars[i])
136       msg = "Missing number";
137     else {
138       const struct unit *u;
139       char *end;
140       errno = 0;
141       u64 x = strtoull(pars[i], &end, 0);
142       if (errno == ERANGE)
143         msg = cf_rngerr;
144       else if (u = lookup_unit(pars[i], end, &msg)) {
145         if (x > ~(u64)0 / u->num)
146           msg = "Number out of range";
147         else {
148           x *= u->num;
149           if (x % u->den)
150             msg = "Number is not an integer";
151           else
152             ptr[i] = x / u->den;
153         }
154       } else
155         ptr[i] = x;
156     }
157     if (msg)
158       return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
159   }
160   return NULL;
161 }
162
163 byte *
164 cf_parse_double(uns number, byte **pars, double *ptr)
165 {
166   for (uns i=0; i<number; i++)
167   {
168     byte *msg = NULL;
169     if (!*pars[i])
170       msg = "Missing number";
171     else {
172       const struct unit *u;
173       char *end;
174       errno = 0;
175       double x = strtoul(pars[i], &end, 0);
176       if (errno == ERANGE)
177         msg = cf_rngerr;
178       else if (u = lookup_unit(pars[i], end, &msg))
179         ptr[i] = x * u->num / u->den;
180       else
181         ptr[i] = x;
182     }
183     if (msg)
184       return number==1 ? msg : cf_printf("Item #%d: %s", i+1, msg);
185   }
186   return NULL;
187 }
188
189 static byte *
190 cf_parse_string(uns number, byte **pars, byte **ptr)
191 {
192   for (uns i=0; i<number; i++)
193     ptr[i] = cf_strdup(pars[i]);
194   return NULL;
195 }
196
197 /* Register size of and parser for each basic type */
198 static struct {
199   uns size;
200   void *parser;
201 } parsers[] = {
202   { sizeof(int), cf_parse_int },
203   { sizeof(u64), cf_parse_u64 },
204   { sizeof(double), cf_parse_double },
205   { sizeof(byte*), cf_parse_string }
206 };
207
208 static byte *
209 cf_parse_dyn(uns number, byte **pars, void **ptr, enum cf_type type)
210 {
211   cf_journal_block(ptr, sizeof(void*));
212   *ptr = cf_malloc((number+1) * parsers[type].size) + parsers[type].size;
213   * (uns*) (ptr - parsers[type].size) = number;
214   return ((cf_parser*) parsers[type].parser) (number, pars, *ptr);
215 }