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 12081 : 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 585 : const char *p;
55 12081 : int64_t res = init;
56 12081 : unsigned def_mult = 1;
57 :
58 12081 : if (def_unit != NULL) {
59 : const struct units *u;
60 :
61 120810 : for (u = units; u->name; ++u) {
62 120810 : if (strcasecmp (u->name, def_unit) == 0) {
63 12081 : def_mult = u->mult;
64 12081 : break;
65 : }
66 : }
67 12081 : if (u->name == NULL)
68 0 : return -1;
69 : }
70 :
71 12081 : p = s;
72 24162 : 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 12081 : int no_val_p = 0;
79 :
80 12081 : while (isspace((unsigned char)*p) || *p == ',')
81 0 : ++p;
82 :
83 12081 : val = strtoll(p, &next, 0);
84 12081 : 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 12081 : p = next;
91 12113 : while (isspace((unsigned char)*p))
92 32 : ++p;
93 12081 : if (*p == '\0') {
94 0 : res = (*func)(res, val, def_mult);
95 0 : if (res < 0)
96 0 : return res;
97 0 : break;
98 12081 : } else if (*p == '+') {
99 0 : ++p;
100 0 : val = 1;
101 12081 : } else if (*p == '-') {
102 0 : ++p;
103 0 : val = -1;
104 : }
105 12081 : if (no_val_p && val == 0)
106 0 : val = 1;
107 12081 : u_len = strcspn (p, ", \t");
108 12081 : partial = 0;
109 12081 : partial_unit = NULL;
110 12081 : if (u_len > 1 && p[u_len - 1] == 's')
111 32 : --u_len;
112 72364 : for (u = units; u->name; ++u) {
113 72364 : if (strncasecmp (p, u->name, u_len) == 0) {
114 24133 : if (u_len == strlen (u->name)) {
115 12081 : p += u_len;
116 12081 : res = (*func)(res, val, u->mult);
117 12081 : if (res < 0)
118 0 : return res;
119 11496 : break;
120 : } else {
121 12052 : ++partial;
122 12052 : partial_unit = u;
123 : }
124 : }
125 : }
126 12081 : 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 12081 : if (*p == 's')
137 32 : ++p;
138 12081 : while (isspace((unsigned char)*p))
139 0 : ++p;
140 : }
141 11496 : 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 0 : 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 12081 : acc_units(int64_t res, int64_t val, uint64_t mult)
247 : {
248 12081 : return res + val * mult;
249 : }
250 :
251 : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
252 12081 : parse_units (const char *s, const struct units *units,
253 : const char *def_unit)
254 : {
255 12081 : 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, uint64_t orig)
279 : {
280 0 : return parse_something_unsigned (s, units, NULL, acc_flags, orig, 1);
281 : }
282 :
283 : /*
284 : * Return a string representation according to `units' of `num' in `s'
285 : * with maximum length `len'. The actual length is the function value.
286 : */
287 :
288 : static int
289 0 : unparse_something_signed(int64_t num, const struct units *units, char *s,
290 : size_t len,
291 : int64_t (*get_divisor)(int64_t, uint64_t),
292 : int (*print)(char *, size_t, int64_t, const char *, int64_t),
293 : int64_t (*update)(int64_t, uint64_t),
294 : const char *zero_string)
295 : {
296 0 : const struct units *u;
297 0 : int ret = 0, tmp;
298 :
299 0 : if (num == 0)
300 0 : return snprintf (s, len, "%s", zero_string);
301 0 : if (len)
302 0 : s[0] = '\0';
303 0 : if (num < 0)
304 0 : return -1;
305 :
306 0 : for (u = units; num > 0 && u->name; ++u) {
307 0 : long long divisor = get_divisor(num, u->mult);
308 :
309 0 : if (divisor) {
310 0 : num = (*update)(num, u->mult);
311 0 : tmp = (*print)(s, len, divisor, u->name, num);
312 0 : if (tmp < 0)
313 0 : return tmp;
314 0 : if ((size_t)tmp > len) {
315 0 : len = 0;
316 0 : s = NULL;
317 : } else {
318 0 : len -= tmp;
319 0 : s += tmp;
320 : }
321 0 : ret += tmp;
322 : }
323 : }
324 0 : return ret;
325 : }
326 :
327 : static int
328 130750 : unparse_something_unsigned(uint64_t num, const struct units *units, char *s,
329 : size_t len,
330 : uint64_t (*get_divisor)(uint64_t, uint64_t),
331 : int (*print)(char *, size_t, uint64_t, const char *, uint64_t),
332 : uint64_t (*update)(uint64_t, uint64_t),
333 : const char *zero_string)
334 : {
335 4486 : const struct units *u;
336 4486 : int64_t tmp;
337 130750 : int ret = 0;
338 :
339 130750 : if (num == 0)
340 10649 : return snprintf (s, len, "%s", zero_string);
341 120101 : if (len)
342 120101 : s[0] = '\0';
343 :
344 1773351 : for (u = units; num > 0 && u->name; ++u) {
345 1653250 : long long divisor = get_divisor(num, u->mult);
346 :
347 1653250 : if (divisor) {
348 209494 : num = (*update) (num, u->mult);
349 209494 : tmp = (*print) (s, len, divisor, u->name, num);
350 209494 : if (tmp < 0)
351 0 : return tmp;
352 209494 : if ((size_t)tmp > len) {
353 0 : len = 0;
354 0 : s = NULL;
355 : } else {
356 209494 : len -= tmp;
357 209494 : s += tmp;
358 : }
359 209494 : ret += tmp;
360 : }
361 : }
362 115615 : return ret;
363 : }
364 :
365 : static int
366 0 : print_unit(char *s, size_t len, int64_t divisor, const char *name, int64_t rem)
367 : {
368 0 : return snprintf(s, len, "%lld %s%s%s", (long long)divisor, name,
369 : divisor == 1 ? "" : "s", rem > 0 ? " " : "");
370 : }
371 :
372 : static int64_t
373 0 : get_divisor_unit(int64_t in, uint64_t mult)
374 : {
375 0 : return in / mult;
376 : }
377 :
378 : static int64_t
379 0 : update_unit(int64_t in, uint64_t mult)
380 : {
381 0 : return in % mult;
382 : }
383 :
384 : static int64_t
385 0 : update_unit_approx(int64_t in, uint64_t mult)
386 : {
387 0 : if (in / mult > 0)
388 0 : return 0;
389 : else
390 0 : return update_unit (in, mult);
391 : }
392 :
393 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
394 0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
395 : {
396 0 : return unparse_something_signed(num, units, s, len,
397 : get_divisor_unit, print_unit, update_unit,
398 : "0");
399 : }
400 :
401 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
402 0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
403 : {
404 0 : return unparse_something_signed(num, units, s, len, get_divisor_unit,
405 : print_unit, update_unit_approx, "0");
406 : }
407 :
408 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
409 0 : print_units_table (const struct units *units, FILE *f)
410 : {
411 0 : const struct units *u, *u2;
412 0 : size_t max_sz = 0;
413 :
414 0 : for (u = units; u->name; ++u) {
415 0 : max_sz = max(max_sz, strlen(u->name));
416 : }
417 :
418 0 : for (u = units; u->name;) {
419 0 : char buf[1024];
420 0 : const struct units *next;
421 :
422 0 : for (next = u + 1; next->name && next->mult == u->mult; ++next)
423 : ;
424 :
425 0 : if (next->name) {
426 0 : for (u2 = next;
427 0 : u2->name && u->mult % u2->mult != 0;
428 0 : ++u2)
429 : ;
430 0 : if (u2->name == NULL)
431 0 : --u2;
432 0 : unparse_units (u->mult, u2, buf, sizeof(buf));
433 0 : fprintf (f, "1 %*s = %s\n", (int)max_sz, u->name, buf);
434 : } else {
435 0 : fprintf (f, "1 %s\n", u->name);
436 : }
437 0 : u = next;
438 : }
439 0 : }
440 :
441 : static uint64_t
442 1653250 : get_divisor_flag(uint64_t in, uint64_t mult)
443 : {
444 1653250 : return in & mult;
445 : }
446 :
447 : static int
448 209494 : print_flag(char *s, size_t len, uint64_t divisor, const char *name, uint64_t rem)
449 : {
450 209494 : return snprintf (s, len, "%s%s", name, rem > 0 ? ", " : "");
451 : }
452 :
453 : static uint64_t
454 209494 : update_flag(uint64_t in, uint64_t mult)
455 : {
456 209494 : return in & ~mult;
457 : }
458 :
459 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
460 130750 : unparse_flags (uint64_t num, const struct units *units, char *s, size_t len)
461 : {
462 130750 : return unparse_something_unsigned(num, units, s, len, get_divisor_flag,
463 : print_flag, update_flag, "");
464 : }
465 :
466 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
467 0 : print_flags_table (const struct units *units, FILE *f)
468 : {
469 0 : const struct units *u;
470 :
471 0 : for(u = units; u->name; ++u)
472 0 : fprintf(f, "%s%s", u->name, (u+1)->name ? ", " : "\n");
473 0 : }
474 :
475 : #undef parse_units
476 : #undef unparse_units
477 : #undef unparse_units_approx
478 : #undef print_units_table
479 : #undef parse_flags
480 : #undef unparse_flags
481 : #undef print_flags_table
482 :
483 : ROKEN_LIB_FUNCTION int64_t ROKEN_LIB_CALL
484 0 : parse_units(const char *s, const struct units *units,
485 : const char *def_unit)
486 : {
487 0 : return rk_parse_units(s, units, def_unit);
488 : }
489 :
490 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
491 0 : unparse_units(int64_t num, const struct units *units, char *s, size_t len)
492 : {
493 0 : return rk_unparse_units(num, units, s, len);
494 : }
495 :
496 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
497 0 : unparse_units_approx(int64_t num, const struct units *units, char *s, size_t len)
498 : {
499 0 : return rk_unparse_units_approx(num, units, s, len);
500 : }
501 :
502 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
503 0 : print_units_table(const struct units *units, FILE *f)
504 : {
505 0 : rk_print_units_table(units, f);
506 0 : }
507 :
508 : ROKEN_LIB_FUNCTION uint64_t ROKEN_LIB_CALL
509 0 : parse_flags(const char *s, const struct units *units, int orig)
510 : {
511 0 : return rk_parse_flags(s, units, orig);
512 : }
513 :
514 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
515 0 : unparse_flags(uint64_t num, const struct units *units, char *s, size_t len)
516 : {
517 0 : return rk_unparse_flags(num, units, s, len);
518 : }
519 :
520 : ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
521 0 : print_flags_table (const struct units *units, FILE *f)
522 : {
523 0 : rk_print_flags_table(units, f);
524 0 : }
|