]> mj.ucw.cz Git - libucw.git/blob - ucw/conf-parse.c
Doc: Updated the list of contributors
[libucw.git] / ucw / conf-parse.c
1 /*
2  *      UCW Library -- Configuration files: parsers for basic types
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 <ucw/lib.h>
12 #include <ucw/conf.h>
13 #include <ucw/chartype.h>
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <errno.h>
18
19 struct unit {
20   uns name;                     // one-letter name of the unit
21   uns num, den;                 // fraction
22 };
23
24 static const struct unit units[] = {
25   { 'd', 86400, 1 },
26   { 'h', 3600, 1 },
27   { 'k', 1000, 1 },
28   { 'm', 1000000, 1 },
29   { 'g', 1000000000, 1 },
30   { 'K', 1024, 1 },
31   { 'M', 1048576, 1 },
32   { 'G', 1073741824, 1 },
33   { '%', 1, 100 },
34   { 0, 0, 0 }
35 };
36
37 static const struct unit *
38 lookup_unit(const char *value, const char *end, char **msg)
39 {
40   if (end && *end) {
41     if (end == value || end[1] || *end >= '0' && *end <= '9')
42       *msg = "Invalid number";
43     else {
44       for (const struct unit *u=units; u->name; u++)
45         if ((char)u->name == *end)
46           return u;
47       *msg = "Invalid unit";
48     }
49   }
50   return NULL;
51 }
52
53 static char cf_rngerr[] = "Number out of range";
54
55 char *
56 cf_parse_int(const char *str, int *ptr)
57 {
58   char *msg = NULL;
59   if (!*str)
60     msg = "Missing number";
61   else {
62     const struct unit *u;
63     char *end;
64     errno = 0;
65     uns x = strtoul(str, &end, 0);
66     if (errno == ERANGE)
67       msg = cf_rngerr;
68     else if (u = lookup_unit(str, end, &msg)) {
69       u64 y = (u64)x * u->num;
70       if (y % u->den)
71         msg = "Number is not an integer";
72       else {
73         y /= u->den;
74         if (y > 0xffffffff)
75           msg = cf_rngerr;
76         *ptr = y;
77       }
78     } else
79       *ptr = x;
80   }
81   return msg;
82 }
83
84 char *
85 cf_parse_u64(const char *str, u64 *ptr)
86 {
87   char *msg = NULL;
88   if (!*str)
89     msg = "Missing number";
90   else {
91     const struct unit *u;
92     char *end;
93     errno = 0;
94     u64 x = strtoull(str, &end, 0);
95     if (errno == ERANGE)
96       msg = cf_rngerr;
97     else if (u = lookup_unit(str, end, &msg)) {
98       if (x > ~(u64)0 / u->num)
99         msg = "Number out of range";
100       else {
101         x *= u->num;
102         if (x % u->den)
103           msg = "Number is not an integer";
104         else
105           *ptr = x / u->den;
106       }
107     } else
108       *ptr = x;
109   }
110   return msg;
111 }
112
113 char *
114 cf_parse_double(const char *str, double *ptr)
115 {
116   char *msg = NULL;
117   if (!*str)
118     msg = "Missing number";
119   else {
120     const struct unit *u;
121     double x;
122     uns read_chars;
123     if (sscanf(str, "%lf%n", &x, &read_chars) != 1)
124       msg = "Invalid number";
125     else if (u = lookup_unit(str, str + read_chars, &msg))
126       *ptr = x * u->num / u->den;
127     else
128       *ptr = x;
129   }
130   return msg;
131 }
132
133 char *
134 cf_parse_ip(const char *p, u32 *varp)
135 {
136   if (!*p)
137     return "Missing IP address";
138   uns x = 0;
139   char *p2;
140   if (*p == '0' && (p[1] | 32) == 'x' && Cxdigit(p[2])) {
141     errno = 0;
142     x = strtoul(p, &p2, 16);
143     if (errno == ERANGE || x > 0xffffffff)
144       goto error;
145     p = p2;
146   }
147   else
148     for (uns i = 0; i < 4; i++) {
149       if (i) {
150         if (*p++ != '.')
151           goto error;
152       }
153       if (!Cdigit(*p))
154         goto error;
155       errno = 0;
156       uns y = strtoul(p, &p2, 10);
157       if (errno == ERANGE || p2 == (char*) p || y > 255)
158         goto error;
159       p = p2;
160       x = (x << 8) + y;
161     }
162   *varp = x;
163   return *p ? "Trailing characters" : NULL;
164 error:
165   return "Invalid IP address";
166 }
167