blob: 2337b07b96d03c77c5959216420074de016f8b85 [file] [log] [blame]
bigbiff bigbiffe60683a2013-02-22 20:55:50 -05001/*
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <inttypes.h>
9#include <ctype.h>
10#include <errno.h>
11#include <sys/stat.h>
12#include <string.h>
13
14#include "c.h"
15#include "nls.h"
16#include "strutils.h"
17#include "bitops.h"
18
19static int do_scale_by_power (uintmax_t *x, int base, int power)
20{
21 while (power--) {
22 if (UINTMAX_MAX / base < *x)
23 return -2;
24 *x *= base;
25 }
26 return 0;
27}
28
29/*
30 * strtosize() - convert string to size (uintmax_t).
31 *
32 * Supported suffixes:
33 *
34 * XiB or X for 2^N
35 * where X = {K,M,G,T,P,E,Y,Z}
36 * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only)
37 * for example:
38 * 10KiB = 10240
39 * 10K = 10240
40 *
41 * XB for 10^N
42 * where X = {K,M,G,T,P,E,Y,Z}
43 * for example:
44 * 10KB = 10000
45 *
46 * Note that the function does not accept numbers with '-' (negative sign)
47 * prefix.
48 */
49int strtosize(const char *str, uintmax_t *res)
50{
51 char *p;
52 uintmax_t x;
53 int base = 1024, rc = 0;
54
55 *res = 0;
56
57 if (!str || !*str)
58 goto err;
59
60 /* Only positive numbers are acceptable
61 *
62 * Note that this check is not perfect, it would be better to
63 * use lconv->negative_sign. But coreutils use the same solution,
64 * so it's probably good enough...
65 */
66 p = (char *) str;
67 while (isspace((unsigned char) *p))
68 p++;
69 if (*p == '-')
70 goto err;
71 p = NULL;
72
73 errno = 0;
74 x = strtoumax(str, &p, 0);
75
76 if (p == str ||
77 (errno != 0 && (x == UINTMAX_MAX || x == 0)))
78 goto err;
79
80 if (!p || !*p)
81 goto done; /* without suffix */
82
83 /*
84 * Check size suffixes
85 */
86 if (*(p + 1) == 'i' && *(p + 2) == 'B' && !*(p + 3))
87 base = 1024; /* XiB, 2^N */
88 else if (*(p + 1) == 'B' && !*(p + 2))
89 base = 1000; /* XB, 10^N */
90 else if (*(p + 1))
91 goto err; /* unexpected suffix */
92
93 switch(*p) {
94 case 'K':
95 case 'k':
96 rc = do_scale_by_power(&x, base, 1);
97 break;
98 case 'M':
99 case 'm':
100 rc = do_scale_by_power(&x, base, 2);
101 break;
102 case 'G':
103 case 'g':
104 rc = do_scale_by_power(&x, base, 3);
105 break;
106 case 'T':
107 case 't':
108 rc = do_scale_by_power(&x, base, 4);
109 break;
110 case 'P':
111 case 'p':
112 rc = do_scale_by_power(&x, base, 5);
113 break;
114 case 'E':
115 case 'e':
116 rc = do_scale_by_power(&x, base, 6);
117 break;
118 case 'Z':
119 rc = do_scale_by_power(&x, base, 7);
120 break;
121 case 'Y':
122 rc = do_scale_by_power(&x, base, 8);
123 break;
124 default:
125 goto err;
126 }
127
128done:
129 *res = x;
130 return rc;
131err:
132 return -1;
133}
134
135#ifndef HAVE_MEMPCPY
136void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
137{
138 return ((char *)memcpy(dest, src, n)) + n;
139}
140#endif
141
142#ifndef HAVE_STRNLEN
143size_t strnlen(const char *s, size_t maxlen)
144{
145 int i;
146
147 for (i = 0; i < maxlen; i++) {
148 if (s[i] == '\0')
149 return i + 1;
150 }
151 return maxlen;
152}
153#endif
154
155#ifndef HAVE_STRNCHR
156char *strnchr(const char *s, size_t maxlen, int c)
157{
158 for (; maxlen-- && *s != '\0'; ++s)
159 if (*s == (char)c)
160 return (char *)s;
161 return NULL;
162}
163#endif
164
165#ifndef HAVE_STRNDUP
166char *strndup(const char *s, size_t n)
167{
168 size_t len = strnlen(s, n);
169 char *new = (char *) malloc((len + 1) * sizeof(char));
170 if (!new)
171 return NULL;
172 new[len] = '\0';
173 return (char *) memcpy(new, s, len);
174}
175#endif
176
177int16_t strtos16_or_err(const char *str, const char *errmesg)
178{
179 int32_t num = strtos32_or_err(str, errmesg);
180
181 if (num < INT16_MIN || num > INT16_MAX)
182 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
183
184 return num;
185}
186
187uint16_t strtou16_or_err(const char *str, const char *errmesg)
188{
189 uint32_t num = strtou32_or_err(str, errmesg);
190
191 if (num > UINT16_MAX)
192 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
193
194 return num;
195}
196
197int32_t strtos32_or_err(const char *str, const char *errmesg)
198{
199 int64_t num = strtos64_or_err(str, errmesg);
200
201 if (num < INT32_MIN || num > INT32_MAX)
202 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
203
204 return num;
205}
206
207uint32_t strtou32_or_err(const char *str, const char *errmesg)
208{
209 uint64_t num = strtou64_or_err(str, errmesg);
210
211 if (num > UINT32_MAX)
212 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
213
214 return num;
215}
216
217int64_t strtos64_or_err(const char *str, const char *errmesg)
218{
219 int64_t num;
220 char *end = NULL;
221
222 if (str == NULL || *str == '\0')
223 goto err;
224 errno = 0;
225 num = strtoimax(str, &end, 10);
226
227 if (errno || str == end || (end && *end))
228 goto err;
229
230 return num;
231err:
232 if (errno)
233 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
234
235 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
236}
237
238uint64_t strtou64_or_err(const char *str, const char *errmesg)
239{
240 uintmax_t num;
241 char *end = NULL;
242
243 if (str == NULL || *str == '\0')
244 goto err;
245 errno = 0;
246 num = strtoumax(str, &end, 10);
247
248 if (errno || str == end || (end && *end))
249 goto err;
250
251 return num;
252err:
253 if (errno)
254 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
255
256 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
257}
258
259
260double strtod_or_err(const char *str, const char *errmesg)
261{
262 double num;
263 char *end = NULL;
264
265 if (str == NULL || *str == '\0')
266 goto err;
267 errno = 0;
268 num = strtod(str, &end);
269
270 if (errno || str == end || (end && *end))
271 goto err;
272
273 return num;
274err:
275 if (errno)
276 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
277
278 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
279}
280
281long strtol_or_err(const char *str, const char *errmesg)
282{
283 long num;
284 char *end = NULL;
285
286 if (str == NULL || *str == '\0')
287 goto err;
288 errno = 0;
289 num = strtol(str, &end, 10);
290
291 if (errno || str == end || (end && *end))
292 goto err;
293
294 return num;
295err:
296 if (errno)
297 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
298 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
299}
300
301unsigned long strtoul_or_err(const char *str, const char *errmesg)
302{
303 unsigned long num;
304 char *end = NULL;
305
306 if (str == NULL || *str == '\0')
307 goto err;
308 errno = 0;
309 num = strtoul(str, &end, 10);
310
311 if (errno || str == end || (end && *end))
312 goto err;
313
314 return num;
315err:
316 if (errno)
317 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
318
319 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
320}
321
322uintmax_t strtosize_or_err(const char *str, const char *errmesg)
323{
324 uintmax_t num;
325
326 if (strtosize(str, &num) == 0)
327 return num;
328
329 if (errno)
330 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
331
332 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
333}
334
335/*
336 * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
337 * be 10 bytes.
338 */
339void strmode(mode_t mode, char *str)
340{
341 if (S_ISDIR(mode))
342 str[0] = 'd';
343 else if (S_ISLNK(mode))
344 str[0] = 'l';
345 else if (S_ISCHR(mode))
346 str[0] = 'c';
347 else if (S_ISBLK(mode))
348 str[0] = 'b';
349 else if (S_ISSOCK(mode))
350 str[0] = 's';
351 else if (S_ISFIFO(mode))
352 str[0] = 'p';
353 else if (S_ISREG(mode))
354 str[0] = '-';
355
356 str[1] = mode & S_IRUSR ? 'r' : '-';
357 str[2] = mode & S_IWUSR ? 'w' : '-';
358 str[3] = (mode & S_ISUID
359 ? (mode & S_IXUSR ? 's' : 'S')
360 : (mode & S_IXUSR ? 'x' : '-'));
361 str[4] = mode & S_IRGRP ? 'r' : '-';
362 str[5] = mode & S_IWGRP ? 'w' : '-';
363 str[6] = (mode & S_ISGID
364 ? (mode & S_IXGRP ? 's' : 'S')
365 : (mode & S_IXGRP ? 'x' : '-'));
366 str[7] = mode & S_IROTH ? 'r' : '-';
367 str[8] = mode & S_IWOTH ? 'w' : '-';
368 str[9] = (mode & S_ISVTX
369 ? (mode & S_IXOTH ? 't' : 'T')
370 : (mode & S_IXOTH ? 'x' : '-'));
371 str[10] = '\0';
372}
373
374/*
375 * returns exponent (2^x=n) in range KiB..PiB
376 */
377static int get_exp(uint64_t n)
378{
379 int shft;
380
381 for (shft = 10; shft <= 60; shft += 10) {
382 if (n < (1ULL << shft))
383 break;
384 }
385 return shft - 10;
386}
387
388char *size_to_human_string(int options, uint64_t bytes)
389{
390 char buf[32];
391 int dec, exp;
392 uint64_t frac;
393 const char *letters = "BKMGTPE";
394 char suffix[sizeof(" KiB")], *psuf = suffix;
395 char c;
396
397 if (options & SIZE_SUFFIX_SPACE)
398 *psuf++ = ' ';
399
400 exp = get_exp(bytes);
401 c = *(letters + (exp ? exp / 10 : 0));
402 dec = exp ? bytes / (1ULL << exp) : bytes;
403 frac = exp ? bytes % (1ULL << exp) : 0;
404
405 *psuf++ = c;
406
407 if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) {
408 *psuf++ = 'i';
409 *psuf++ = 'B';
410 }
411
412 *psuf = '\0';
413
414 /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n",
415 * exp, suffix[0], dec, frac);
416 */
417
418 if (frac) {
419 /* round */
420 frac = (frac / (1ULL << (exp - 10)) + 50) / 100;
421 if (frac == 10)
422 dec++, frac = 0;
423 }
424
425 if (frac) {
426 struct lconv const *l = localeconv();
427 char *dp = l ? l->decimal_point : NULL;
428
429 if (!dp || !*dp)
430 dp = ".";
431 snprintf(buf, sizeof(buf), "%d%s%jd%s", dec, dp, frac, suffix);
432 } else
433 snprintf(buf, sizeof(buf), "%d%s", dec, suffix);
434
435 return strdup(buf);
436}
437
438/*
439 * Parses comma delimited list to array with IDs, for example:
440 *
441 * "aaa,bbb,ccc" --> ary[0] = FOO_AAA;
442 * ary[1] = FOO_BBB;
443 * ary[3] = FOO_CCC;
444 *
445 * The function name2id() provides conversion from string to ID.
446 *
447 * Returns: >= 0 : number of items added to ary[]
448 * -1 : parse error or unknown item
449 * -2 : arysz reached
450 */
451int string_to_idarray(const char *list, int ary[], size_t arysz,
452 int (name2id)(const char *, size_t))
453{
454 const char *begin = NULL, *p;
455 size_t n = 0;
456
457 if (!list || !*list || !ary || !arysz || !name2id)
458 return -1;
459
460 for (p = list; p && *p; p++) {
461 const char *end = NULL;
462 int id;
463
464 if (n >= arysz)
465 return -2;
466 if (!begin)
467 begin = p; /* begin of the column name */
468 if (*p == ',')
469 end = p; /* terminate the name */
470 if (*(p + 1) == '\0')
471 end = p + 1; /* end of string */
472 if (!begin || !end)
473 continue;
474 if (end <= begin)
475 return -1;
476
477 id = name2id(begin, end - begin);
478 if (id == -1)
479 return -1;
480 ary[ n++ ] = id;
481 begin = NULL;
482 if (end && !*end)
483 break;
484 }
485 return n;
486}
487
488/*
489 * Parses the array like string_to_idarray but if format is "+aaa,bbb"
490 * it adds fields to array instead of replacing them.
491 */
492int string_add_to_idarray(const char *list, int ary[], size_t arysz,
493 int *ary_pos, int (name2id)(const char *, size_t))
494{
495 const char *list_add;
496 int r;
497
498 if (!list || !*list || !ary_pos ||
499 *ary_pos < 0 || (size_t) *ary_pos > arysz)
500 return -1;
501
502 if (list[0] == '+')
503 list_add = &list[1];
504 else {
505 list_add = list;
506 *ary_pos = 0;
507 }
508
509 r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id);
510 if (r > 0)
511 *ary_pos += r;
512 return r;
513}
514
515/*
516 * LIST ::= <item> [, <item>]
517 *
518 * The <item> is translated to 'id' by name2id() function and the 'id' is used
519 * as a position in the 'ary' bit array. It means that the 'id' has to be in
520 * range <0..N> where N < sizeof(ary) * NBBY.
521 *
522 * Returns: 0 on success, <0 on error.
523 */
524int string_to_bitarray(const char *list,
525 char *ary,
526 int (*name2bit)(const char *, size_t))
527{
528 const char *begin = NULL, *p;
529
530 if (!list || !name2bit || !ary)
531 return -EINVAL;
532
533 for (p = list; p && *p; p++) {
534 const char *end = NULL;
535 int bit;
536
537 if (!begin)
538 begin = p; /* begin of the level name */
539 if (*p == ',')
540 end = p; /* terminate the name */
541 if (*(p + 1) == '\0')
542 end = p + 1; /* end of string */
543 if (!begin || !end)
544 continue;
545 if (end <= begin)
546 return -1;
547
548 bit = name2bit(begin, end - begin);
549 if (bit < 0)
550 return bit;
551 setbit(ary, bit);
552 begin = NULL;
553 if (end && !*end)
554 break;
555 }
556 return 0;
557}
558
559/*
560 * LIST ::= <item> [, <item>]
561 *
562 * The <item> is translated to 'id' by name2flag() function and the flags is
563 * set to the 'mask'
564*
565 * Returns: 0 on success, <0 on error.
566 */
567int string_to_bitmask(const char *list,
568 unsigned long *mask,
569 long (*name2flag)(const char *, size_t))
570{
571 const char *begin = NULL, *p;
572
573 if (!list || !name2flag || !mask)
574 return -EINVAL;
575
576 for (p = list; p && *p; p++) {
577 const char *end = NULL;
578 long flag;
579
580 if (!begin)
581 begin = p; /* begin of the level name */
582 if (*p == ',')
583 end = p; /* terminate the name */
584 if (*(p + 1) == '\0')
585 end = p + 1; /* end of string */
586 if (!begin || !end)
587 continue;
588 if (end <= begin)
589 return -1;
590
591 flag = name2flag(begin, end - begin);
592 if (flag < 0)
593 return flag; /* error */
594 *mask |= flag;
595 begin = NULL;
596 if (end && !*end)
597 break;
598 }
599 return 0;
600}
601
602/*
603 * Parse the lower and higher values in a string containing
604 * "lower:higher" or "lower-higher" format. Note that either
605 * the lower or the higher values may be missing, and the def
606 * value will be assigned to it by default.
607 *
608 * Returns: 0 on success, <0 on error.
609 */
610int parse_range(const char *str, int *lower, int *upper, int def)
611{
612 char *end = NULL;
613
614 if (!str)
615 return 0;
616
617 *upper = *lower = def;
618 errno = 0;
619
620 if (*str == ':') { /* <:N> */
621 str++;
622 *upper = strtol(str, &end, 10);
623 if (errno || !end || *end || end == str)
624 return -1;
625 } else {
626 *upper = *lower = strtol(str, &end, 10);
627 if (errno || !end || end == str)
628 return -1;
629
630 if (*end == ':' && !*(end + 1)) /* <M:> */
631 *upper = 0;
632 else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
633 str = end + 1;
634 end = NULL;
635 errno = 0;
636 *upper = strtol(str, &end, 10);
637
638 if (errno || !end || *end || end == str)
639 return -1;
640 }
641 }
642 return 0;
643}
644
645/*
646 * Compare two strings for equality, ignoring at most one trailing
647 * slash.
648 */
649int streq_except_trailing_slash(const char *s1, const char *s2)
650{
651 int equal;
652
653 if (!s1 && !s2)
654 return 1;
655 if (!s1 || !s2)
656 return 0;
657
658 equal = !strcmp(s1, s2);
659
660 if (!equal) {
661 size_t len1 = strlen(s1);
662 size_t len2 = strlen(s2);
663
664 if (len1 && *(s1 + len1 - 1) == '/')
665 len1--;
666 if (len2 && *(s2 + len2 - 1) == '/')
667 len2--;
668 if (len1 != len2)
669 return 0;
670
671 equal = !strncmp(s1, s2, len1);
672 }
673
674 return equal;
675}
676
677
678#ifdef TEST_PROGRAM
679
680int main(int argc, char *argv[])
681{
682 uintmax_t size = 0;
683 char *hum, *hum2;
684
685 if (argc < 2) {
686 fprintf(stderr, "usage: %s <number>[suffix]\n", argv[0]);
687 exit(EXIT_FAILURE);
688 }
689
690 if (strtosize(argv[1], &size))
691 errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
692
693 hum = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
694 hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER |
695 SIZE_SUFFIX_SPACE, size);
696
697 printf("%25s : %20ju : %8s : %12s\n", argv[1], size, hum, hum2);
698 free(hum);
699 free(hum2);
700
701 return EXIT_SUCCESS;
702}
703#endif /* TEST_PROGRAM */