Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3 : * (Royal Institute of Technology, Stockholm, Sweden).
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions
8 : * are met:
9 : *
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : *
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : *
17 : * 3. Neither the name of the Institute nor the names of its contributors
18 : * may be used to endorse or promote products derived from this software
19 : * without specific prior written permission.
20 : *
21 : * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 : * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 : * SUCH DAMAGE.
32 : */
33 :
34 : #include <config.h>
35 :
36 : #include <stdio.h>
37 : #include <ctype.h>
38 : #include <string.h>
39 : #include "roken.h"
40 : #include "parse_units.h"
41 :
42 : /*
43 : * Parse string in `s' according to `units' and return value.
44 : * def_unit defines the default unit.
45 : */
46 :
47 : static int64_t
48 7085 : parse_something_signed(const char *s, const struct units *units,
49 : const char *def_unit,
50 : int64_t (*func)(int64_t res, int64_t val, uint64_t mult),
51 : int64_t init,
52 : int accept_no_val_p)
53 : {
54 : const char *p;
55 7085 : int64_t res = init;
56 7085 : unsigned def_mult = 1;
57 :
58 7085 : if (def_unit != NULL) {
59 : const struct units *u;
60 :
61 70850 : for (u = units; u->name; ++u) {
62 70850 : if (strcasecmp (u->name, def_unit) == 0) {
63 7085 : def_mult = u->mult;
64 7085 : break;
65 : }
66 : }
67 7085 : if (u->name == NULL)
68 0 : return -1;
69 : }
70 :
71 7085 : p = s;
72 21255 : while (*p) {
73 : int64_t val;
74 : char *next;
75 : const struct units *u, *partial_unit;
76 : size_t u_len;
77 : unsigned partial;
78 7085 : int no_val_p = 0;
79 :
80 14170 : while (isspace((unsigned char)*p) || *p == ',')
81 0 : ++p;
82 :
83 7085 : val = strtoll(p, &next, 0);
84 7085 : if (p == next) {
85 0 : val = 0;
86 0 : if(!accept_no_val_p)
87 0 : return -1;
88 0 : no_val_p = 1;
89 : }
90 7085 : p = next;
91 14179 : while (isspace((unsigned char)*p))
92 9 : ++p;
93 7085 : if (*p == '\0') {
94 0 : res = (*func)(res, val, def_mult);
95 0 : if (res < 0)
96 0 : return res;
97 0 : break;
98 7085 : } else if (*p == '+') {
99 0 : ++p;
100 0 : val = 1;
101 7085 : } else if (*p == '-') {
102 0 : ++p;
103 0 : val = -1;
104 : }
105 7085 : if (no_val_p && val == 0)
106 0 : val = 1;
107 7085 : u_len = strcspn (p, ", \t");
108 7085 : partial = 0;
109 7085 : partial_unit = NULL;
110 7085 : if (u_len > 1 && p[u_len - 1] == 's')
111 9 : --u_len;
112 42480 : for (u = units; u->name; ++u) {
113 42480 : if (strncasecmp (p, u->name, u_len) == 0) {
114 14164 : if (u_len == strlen (u->name)) {
115 7085 : p += u_len;
116 7085 : res = (*func)(res, val, u->mult);
117 7085 : if (res < 0)
118 0 : return res;
119 7085 : break;
120 : } else {
121 7079 : ++partial;
122 7079 : partial_unit = u;
123 : }
124 : }
125 : }
126 7085 : if (u->name == NULL) {
127 0 : if (partial == 1) {
128 0 : p += u_len;
129 0 : res = (*func)(res, val, partial_unit->mult);
130 0 : if (res < 0)
131 0 : return res;
132 : } else {
133 0 : return -1;
134 : }
135 : }
136 7085 : if (*p == 's')
137 9 : ++p;
138 14170 : while (isspace((unsigned char)*p))
139 0 : ++p;
140 : }
141 7085 : return res;
142 : }
143 :
144 : static uint64_t
145 0 : parse_something_unsigned(const char *s, const struct units *units,
146 : const char *def_unit,
147 : uint64_t (*func)(uint64_t res, int64_t val, uint64_t mult),
148 : uint64_t init,
149 : int accept_no_val_p)
150 : {
151 : const char *p;
152 0 : int64_t res = init;
153 0 : unsigned def_mult = 1;
154 :
155 0 : if (def_unit != NULL) {
156 : const struct units *u;
157 :
158 0 : for (u = units; u->name; ++u) {
159 0 : if (strcasecmp (u->name, def_unit) == 0) {
160 0 : def_mult = u->mult;
161 0 : break;
162 : }
163 : }
164 0 : if (u->name == NULL)
165 0 : return -1;
166 : }
167 :
168 0 : p = s;
169 0 : while (*p) {
170 : int64_t val;
171 : char *next;
172 : const struct units *u, *partial_unit;
173 : size_t u_len;
174 : unsigned partial;
175 0 : int no_val_p = 0;
176 :
177 0 : while (isspace((unsigned char)*p) || *p == ',')
178 0 : ++p;
179 :
180 0 : val = strtoll(p, &next, 0);
181 0 : if (p == next) {
182 0 : val = 0;
183 0 : if(!accept_no_val_p)
184 0 : return -1;
185 0 : no_val_p = 1;
186 : }
187 0 : p = next;
188 0 : while (isspace((unsigned char)*p))
189 0 : ++p;
190 0 : if (*p == '\0') {
191 0 : res = (*func)(res, val, def_mult);
192 0 : if (res < 0)
193 0 : return res;
194 0 : break;
195 0 : } else if (*p == '+') {
196 0 : ++p;
197 0 : val = 1;
198 0 : } else if (*p == '-') {
199 0 : ++p;
200 0 : val = -1;
201 : }
202 0 : if (no_val_p && val == 0)
203 0 : val = 1;
204 0 : u_len = strcspn (p, ", \t");
205 0 : partial = 0;
206 0 : partial_unit = NULL;
207 0 : if (u_len > 1 && p[u_len - 1] == 's')
208 0 : --u_len;
209 0 : for (u = units; u->name; ++u) {
210 0 : if (strncasecmp (p, u->name, u_len) == 0) {
211 0 : if (u_len == strlen (u->name)) {
212 0 : p += u_len;
213 0 : res = (*func)(res, val, u->mult);
214 0 : if (res < 0)
215 0 : return res;
216 0 : break;
217 : } else {
218 0 : ++partial;
219 0 : partial_unit = u;
220 : }
221 : }
222 : }
223 0 : if (u->name == NULL) {
224 0 : if (partial == 1) {
225 0 : p += u_len;
226 0 : res = (*func)(res, val, partial_unit->mult);
227 0 : if (res < 0)
228 0 : return res;
229 : } else {
230 0 : return -1;
231 : }
232 : }
233 0 : if (*p == 's')
234 0 : ++p;
235 0 : while (isspace((unsigned char)*p))
236 0 : ++p;
237 : }
238 0 : return res;
239 : }
240 :
241 : /*
242 : * The string consists of a sequence of `n unit'
243 : */
244 :
245 : static int64_t
246 7085 : acc_units(int64_t res, int64_t val, uint64_t mult)
247 : {
248 7085 : return res + val * mult;
249 : }
250 :
251 : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
252 7085 : parse_units (const char *s, const struct units *units,
253 : const char *def_unit)
254 : {
255 7085 : return parse_something_signed(s, units, def_unit, acc_units, 0, 0);
256 : }
257 :
258 : /*
259 : * The string consists of a sequence of `[+-]flag'. `orig' consists
260 : * the original set of flags, those are then modified and returned as
261 : * the function value.
262 : */
263 :
264 : static uint64_t
265 0 : acc_flags(uint64_t res, int64_t val, uint64_t mult)
266 : {
267 0 : if(val == 1)
268 0 : return res | mult;
269 0 : else if(val == -1)
270 0 : return res & ~mult;
271 0 : else if (val == 0)
272 0 : return mult;
273 : else
274 0 : return -1;
275 : }
276 :
277 : ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
278 0 : parse_flags (const char *s, const struct units *units,
279 : int orig)
280 : {
281 0 : return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1);
282 : }
283 :
284 : /*
285 : * Return a string representation according to `units' of `num' in `s'
286 : * with maximum length `len'. The actual length is the function value.
287 : */
288 :
289 : static int
290 0 : unparse_something_signed(int64_t num, const struct units *units, char *s,
291 : size_t len,
292 : int64_t (*get_divisor)(int64_t, uint64_t),
293 : int (*print)(char *, size_t, int64_t, const char *, int64_t),
294 : int64_t (*update)(int64_t, uint64_t),
295 : const char *zero_string)
296 : {
297 : const struct units *u;
298 0 : int ret = 0, tmp;
299 :
300 0 : if (num == 0)
301 0 : return snprintf (s, len, "%s", zero_string);
302 0 : if (len)
303 0 : s[0] = '\0';
304 0 : if (num < 0)
305 0 : return -1;
306 :
307 0 : for (u = units; num > 0 && u->name; ++u) {
308 0 : long long divisor = get_divisor(num, u->mult);
309 :
310 0 : if (divisor) {
311 0 : num = (*update)(num, u->mult);
312 0 : tmp = (*print)(s, len, divisor, u->name, num);
313 0 : if (tmp < 0)
314 0 : return tmp;
315 0 : if ((size_t)tmp > len) {
316 0 : len = 0;
317 0 : s = NULL;
318 : } else {
319 0 : len -= tmp;
320 0 : s += tmp;
321 : }
322 0 : ret += tmp;
323 : }
324 : }
325 0 : return ret;
326 : }
327 :
328 : static int
329 91297 : unparse_something_unsigned(uint64_t num, const struct units *units, char *s,
330 : size_t len,
331 : uint64_t (*get_divisor)(uint64_t, uint64_t),
332 : int (*print)(char *, size_t, uint64_t, const char *, uint64_t),
333 : uint64_t (*update)(uint64_t, uint64_t),
334 : const char *zero_string)
335 : {
336 : const struct units *u;
337 : int64_t tmp;
338 91297 : int ret = 0;
339 :
340 91297 : if (num == 0)
341 9171 : return snprintf (s, len, "%s", zero_string);
342 82126 : if (len)
343 82126 : s[0] = '\0';
344 :
345 1203692 : for (u = units; num > 0 && u->name; ++u) {
346 1121566 : long long divisor = get_divisor(num, u->mult);
347 :
348 1121566 : if (divisor) {
349 141289 : num = (*update) (num, u->mult);
350 141289 : tmp = (*print) (s, len, divisor, u->name, num);
351 141289 : if (tmp < 0)
352 0 : return tmp;
353 141289 : if ((size_t)tmp > len) {
354 0 : len = 0;
355 0 : s = NULL;
356 : } else {
357 141289 : len -= tmp;
358 141289 : s += tmp;
359 : }
360 141289 : ret += tmp;
361 : }
362 : }
363 82126 : return ret;
364 : }
365 :
366 : static int
367 0 : print_unit(char *s, size_t len, int64_t divisor, const char *name, int64_t rem)
368 : {
369 0 : return snprintf(s, len, "%lld %s%s%s", (long long)divisor, name,
370 : divisor == 1 ? "" : "s", rem > 0 ? " " : "");
371 : }
372 :
373 : static int64_t
374 0 : get_divisor_unit(int64_t in, uint64_t mult)
375 : {
376 0 : return in / mult;
377 : }
378 :
379 : static int64_t
380 0 : update_unit(int64_t in, uint64_t mult)
381 : {
382 0 : return in % mult;
383 : }
384 :
385 : static int64_t
386 0 : update_unit_approx(int64_t in, uint64_t mult)
387 : {
388 0 : if (in / mult > 0)
389 0 : return 0;
390 : else
391 0 : return update_unit (in, mult);
392 : }
393 :
394 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
395 0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
396 : {
397 0 : return unparse_something_signed(num, units, s, len,
398 : get_divisor_unit, print_unit, update_unit,
399 : "0");
400 : }
401 :
402 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
403 0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
404 : {
405 0 : return unparse_something_signed(num, units, s, len, get_divisor_unit,
406 : print_unit, update_unit_approx, "0");
407 : }
408 :
409 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
410 0 : print_units_table (const struct units *units, FILE *f)
411 : {
412 : const struct units *u, *u2;
413 0 : size_t max_sz = 0;
414 :
415 0 : for (u = units; u->name; ++u) {
416 0 : max_sz = max(max_sz, strlen(u->name));
417 : }
418 :
419 0 : for (u = units; u->name;) {
420 : char buf[1024];
421 : const struct units *next;
422 :
423 0 : for (next = u + 1; next->name && next->mult == u->mult; ++next)
424 : ;
425 :
426 0 : if (next->name) {
427 0 : for (u2 = next;
428 0 : u2->name && u->mult % u2->mult != 0;
429 0 : ++u2)
430 : ;
431 0 : if (u2->name == NULL)
432 0 : --u2;
433 0 : unparse_units (u->mult, u2, buf, sizeof(buf));
434 0 : fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
435 : } else {
436 0 : fprintf (f, "1 %s\n", u->name);
437 : }
438 0 : u = next;
439 : }
440 0 : }
441 :
442 : static uint64_t
443 1121566 : get_divisor_flag(uint64_t in, uint64_t mult)
444 : {
445 1121566 : return in & mult;
446 : }
447 :
448 : static int
449 141289 : print_flag(char *s, size_t len, uint64_t divisor, const char *name, uint64_t rem)
450 : {
451 141289 : return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
452 : }
453 :
454 : static uint64_t
455 141289 : update_flag(uint64_t in, uint64_t mult)
456 : {
457 141289 : return in & ~mult;
458 : }
459 :
460 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
461 91297 : unparse_flags (uint64_t num, const struct units *units, char *s, size_t len)
462 : {
463 91297 : return unparse_something_unsigned(num, units, s, len, get_divisor_flag,
464 : print_flag, update_flag, "");
465 : }
466 :
467 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
468 0 : print_flags_table (const struct units *units, FILE *f)
469 : {
470 : const struct units *u;
471 :
472 0 : for(u = units; u->name; ++u)
473 0 : fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
474 0 : }
475 :
476 : #undef parse_units
477 : #undef unparse_units
478 : #undef unparse_units_approx
479 : #undef print_units_table
480 : #undef parse_flags
481 : #undef unparse_flags
482 : #undef print_flags_table
483 :
484 : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
485 0 : parse_units(const char *s, const struct units *units,
486 : const char *def_unit)
487 : {
488 0 : return rk_parse_units(s, units, def_unit);
489 : }
490 :
491 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
492 0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
493 : {
494 0 : return rk_unparse_units(num, units, s, len);
495 : }
496 :
497 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
498 0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
499 : {
500 0 : return rk_unparse_units_approx(num, units, s, len);
501 : }
502 :
503 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
504 0 : print_units_table(const struct units *units, FILE *f)
505 : {
506 0 : rk_print_units_table(units, f);
507 0 : }
508 :
509 : ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
510 0 : parse_flags(const char *s, const struct units *units, int orig)
511 : {
512 0 : return rk_parse_flags(s, units, orig);
513 : }
514 :
515 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
516 0 : unparse_flags(uint64_t num, const struct units *units, char *s, size_t len)
517 : {
518 0 : return rk_unparse_flags(num, units, s, len);
519 : }
520 :
521 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
522 0 : print_flags_table (const struct units *units, FILE *f)
523 : {
524 0 : rk_print_flags_table(units, f);
525 0 : }
|