]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/strutils.c
bash-completion/umount: shell charaters escape
[thirdparty/util-linux.git] / lib / strutils.c
1 /*
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3 * Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
4 *
5 * No copyright is claimed. This code is in the public domain; do with
6 * it what you wish.
7 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <inttypes.h>
11 #include <ctype.h>
12 #include <errno.h>
13 #include <sys/stat.h>
14 #include <string.h>
15 #include <assert.h>
16
17 #include "c.h"
18 #include "nls.h"
19 #include "strutils.h"
20 #include "bitops.h"
21 #include "pathnames.h"
22
23 static int STRTOXX_EXIT_CODE = EXIT_FAILURE;
24
25 void strutils_set_exitcode(int ex) {
26 STRTOXX_EXIT_CODE = ex;
27 }
28
29 static int do_scale_by_power (uintmax_t *x, int base, int power)
30 {
31 while (power--) {
32 if (UINTMAX_MAX / base < *x)
33 return -ERANGE;
34 *x *= base;
35 }
36 return 0;
37 }
38
39 /*
40 * strtosize() - convert string to size (uintmax_t).
41 *
42 * Supported suffixes:
43 *
44 * XiB or X for 2^N
45 * where X = {K,M,G,T,P,E,Z,Y}
46 * or X = {k,m,g,t,p,e} (undocumented for backward compatibility only)
47 * for example:
48 * 10KiB = 10240
49 * 10K = 10240
50 *
51 * XB for 10^N
52 * where X = {K,M,G,T,P,E,Z,Y}
53 * for example:
54 * 10KB = 10000
55 *
56 * The optional 'power' variable returns number associated with used suffix
57 * {K,M,G,T,P,E,Z,Y} = {1,2,3,4,5,6,7,8}.
58 *
59 * The function also supports decimal point, for example:
60 * 0.5MB = 500000
61 * 0.5MiB = 512000
62 *
63 * Note that the function does not accept numbers with '-' (negative sign)
64 * prefix.
65 */
66 int parse_size(const char *str, uintmax_t *res, int *power)
67 {
68 const char *p;
69 char *end;
70 uintmax_t x, frac = 0;
71 int base = 1024, rc = 0, pwr = 0, frac_zeros = 0;
72
73 static const char *suf = "KMGTPEZY";
74 static const char *suf2 = "kmgtpezy";
75 const char *sp;
76
77 *res = 0;
78
79 if (!str || !*str) {
80 rc = -EINVAL;
81 goto err;
82 }
83
84 /* Only positive numbers are acceptable
85 *
86 * Note that this check is not perfect, it would be better to
87 * use lconv->negative_sign. But coreutils use the same solution,
88 * so it's probably good enough...
89 */
90 p = str;
91 while (isspace((unsigned char) *p))
92 p++;
93 if (*p == '-') {
94 rc = -EINVAL;
95 goto err;
96 }
97
98 errno = 0, end = NULL;
99 x = strtoumax(str, &end, 0);
100
101 if (end == str ||
102 (errno != 0 && (x == UINTMAX_MAX || x == 0))) {
103 rc = errno ? -errno : -EINVAL;
104 goto err;
105 }
106 if (!end || !*end)
107 goto done; /* without suffix */
108 p = end;
109
110 /*
111 * Check size suffixes
112 */
113 check_suffix:
114 if (*(p + 1) == 'i' && (*(p + 2) == 'B' || *(p + 2) == 'b') && !*(p + 3))
115 base = 1024; /* XiB, 2^N */
116 else if ((*(p + 1) == 'B' || *(p + 1) == 'b') && !*(p + 2))
117 base = 1000; /* XB, 10^N */
118 else if (*(p + 1)) {
119 struct lconv const *l = localeconv();
120 const char *dp = l ? l->decimal_point : NULL;
121 size_t dpsz = dp ? strlen(dp) : 0;
122
123 if (frac == 0 && *p && dp && strncmp(dp, p, dpsz) == 0) {
124 const char *fstr = p + dpsz;
125
126 for (p = fstr; *p == '0'; p++)
127 frac_zeros++;
128 fstr = p;
129 if (isdigit(*fstr)) {
130 errno = 0, end = NULL;
131 frac = strtoumax(fstr, &end, 0);
132 if (end == fstr ||
133 (errno != 0 && (frac == UINTMAX_MAX || frac == 0))) {
134 rc = errno ? -errno : -EINVAL;
135 goto err;
136 }
137 } else
138 end = (char *) p;
139
140 if (frac && (!end || !*end)) {
141 rc = -EINVAL;
142 goto err; /* without suffix, but with frac */
143 }
144 p = end;
145 goto check_suffix;
146 }
147 rc = -EINVAL;
148 goto err; /* unexpected suffix */
149 }
150
151 sp = strchr(suf, *p);
152 if (sp)
153 pwr = (sp - suf) + 1;
154 else {
155 sp = strchr(suf2, *p);
156 if (sp)
157 pwr = (sp - suf2) + 1;
158 else {
159 rc = -EINVAL;
160 goto err;
161 }
162 }
163
164 rc = do_scale_by_power(&x, base, pwr);
165 if (power)
166 *power = pwr;
167 if (frac && pwr) {
168 int i;
169 uintmax_t frac_div = 10, frac_poz = 1, frac_base = 1;
170
171 /* mega, giga, ... */
172 do_scale_by_power(&frac_base, base, pwr);
173
174 /* maximal divisor for last digit (e.g. for 0.05 is
175 * frac_div=100, for 0.054 is frac_div=1000, etc.)
176 *
177 * Reduce frac if too large.
178 */
179 while (frac_div < frac) {
180 if (frac_div <= UINTMAX_MAX/10)
181 frac_div *= 10;
182 else
183 frac /= 10;
184 }
185
186 /* 'frac' is without zeros (5 means 0.5 as well as 0.05) */
187 for (i = 0; i < frac_zeros; i++) {
188 if (frac_div <= UINTMAX_MAX/10)
189 frac_div *= 10;
190 else
191 frac /= 10;
192 }
193
194 /*
195 * Go backwardly from last digit and add to result what the
196 * digit represents in the frac_base. For example 0.25G
197 *
198 * 5 means 1GiB / (100/5)
199 * 2 means 1GiB / (10/2)
200 */
201 do {
202 unsigned int seg = frac % 10; /* last digit of the frac */
203 uintmax_t seg_div = frac_div / frac_poz; /* what represents the segment 1000, 100, .. */
204
205 frac /= 10; /* remove last digit from frac */
206 frac_poz *= 10;
207
208 if (seg && seg_div / seg)
209 x += frac_base / (seg_div / seg);
210 } while (frac);
211 }
212 done:
213 *res = x;
214 err:
215 if (rc < 0)
216 errno = -rc;
217 return rc;
218 }
219
220 int strtosize(const char *str, uintmax_t *res)
221 {
222 return parse_size(str, res, NULL);
223 }
224
225 int isdigit_strend(const char *str, const char **end)
226 {
227 const char *p;
228
229 for (p = str; p && *p && isdigit((unsigned char) *p); p++);
230
231 if (end)
232 *end = p;
233 return p && p > str && !*p;
234 }
235
236 int isxdigit_strend(const char *str, const char **end)
237 {
238 const char *p;
239
240 for (p = str; p && *p && isxdigit((unsigned char) *p); p++);
241
242 if (end)
243 *end = p;
244
245 return p && p > str && !*p;
246 }
247
248 /*
249 * parse_switch(argv[i], "on", "off", "yes", "no", NULL);
250 */
251 int parse_switch(const char *arg, const char *errmesg, ...)
252 {
253 const char *a, *b;
254 va_list ap;
255
256 va_start(ap, errmesg);
257 do {
258 a = va_arg(ap, char *);
259 if (!a)
260 break;
261 b = va_arg(ap, char *);
262 if (!b)
263 break;
264
265 if (strcmp(arg, a) == 0) {
266 va_end(ap);
267 return 1;
268 }
269
270 if (strcmp(arg, b) == 0) {
271 va_end(ap);
272 return 0;
273 }
274 } while (1);
275 va_end(ap);
276
277 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, arg);
278 }
279
280 #ifndef HAVE_MEMPCPY
281 void *mempcpy(void *restrict dest, const void *restrict src, size_t n)
282 {
283 return ((char *)memcpy(dest, src, n)) + n;
284 }
285 #endif
286
287 #ifndef HAVE_STRNLEN
288 size_t strnlen(const char *s, size_t maxlen)
289 {
290 size_t i;
291
292 for (i = 0; i < maxlen; i++) {
293 if (s[i] == '\0')
294 return i;
295 }
296 return maxlen;
297 }
298 #endif
299
300 #ifndef HAVE_STRNCHR
301 char *strnchr(const char *s, size_t maxlen, int c)
302 {
303 for (; maxlen-- && *s != '\0'; ++s)
304 if (*s == (char)c)
305 return (char *)s;
306 return NULL;
307 }
308 #endif
309
310 #ifndef HAVE_STRNDUP
311 char *strndup(const char *s, size_t n)
312 {
313 size_t len = strnlen(s, n);
314 char *new = malloc((len + 1) * sizeof(char));
315 if (!new)
316 return NULL;
317 new[len] = '\0';
318 return (char *) memcpy(new, s, len);
319 }
320 #endif
321
322 static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base);
323 static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base);
324
325 int16_t strtos16_or_err(const char *str, const char *errmesg)
326 {
327 int32_t num = strtos32_or_err(str, errmesg);
328
329 if (num < INT16_MIN || num > INT16_MAX) {
330 errno = ERANGE;
331 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
332 }
333 return num;
334 }
335
336 static uint16_t _strtou16_or_err(const char *str, const char *errmesg, int base)
337 {
338 uint32_t num = _strtou32_or_err(str, errmesg, base);
339
340 if (num > UINT16_MAX) {
341 errno = ERANGE;
342 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
343 }
344 return num;
345 }
346
347 uint16_t strtou16_or_err(const char *str, const char *errmesg)
348 {
349 return _strtou16_or_err(str, errmesg, 10);
350 }
351
352 uint16_t strtox16_or_err(const char *str, const char *errmesg)
353 {
354 return _strtou16_or_err(str, errmesg, 16);
355 }
356
357 int32_t strtos32_or_err(const char *str, const char *errmesg)
358 {
359 int64_t num = strtos64_or_err(str, errmesg);
360
361 if (num < INT32_MIN || num > INT32_MAX) {
362 errno = ERANGE;
363 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
364 }
365 return num;
366 }
367
368 static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base)
369 {
370 uint64_t num = _strtou64_or_err(str, errmesg, base);
371
372 if (num > UINT32_MAX) {
373 errno = ERANGE;
374 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
375 }
376 return num;
377 }
378
379 uint32_t strtou32_or_err(const char *str, const char *errmesg)
380 {
381 return _strtou32_or_err(str, errmesg, 10);
382 }
383
384 uint32_t strtox32_or_err(const char *str, const char *errmesg)
385 {
386 return _strtou32_or_err(str, errmesg, 16);
387 }
388
389 int64_t strtos64_or_err(const char *str, const char *errmesg)
390 {
391 int64_t num;
392 char *end = NULL;
393
394 errno = 0;
395 if (str == NULL || *str == '\0')
396 goto err;
397 num = strtoimax(str, &end, 10);
398
399 if (errno || str == end || (end && *end))
400 goto err;
401
402 return num;
403 err:
404 if (errno == ERANGE)
405 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
406
407 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
408 }
409
410 static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base)
411 {
412 uintmax_t num;
413 char *end = NULL;
414
415 errno = 0;
416 if (str == NULL || *str == '\0')
417 goto err;
418 num = strtoumax(str, &end, base);
419
420 if (errno || str == end || (end && *end))
421 goto err;
422
423 return num;
424 err:
425 if (errno == ERANGE)
426 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
427
428 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
429 }
430
431 uint64_t strtou64_or_err(const char *str, const char *errmesg)
432 {
433 return _strtou64_or_err(str, errmesg, 10);
434 }
435
436 uint64_t strtox64_or_err(const char *str, const char *errmesg)
437 {
438 return _strtou64_or_err(str, errmesg, 16);
439 }
440
441 double strtod_or_err(const char *str, const char *errmesg)
442 {
443 double num;
444 char *end = NULL;
445
446 errno = 0;
447 if (str == NULL || *str == '\0')
448 goto err;
449 num = strtod(str, &end);
450
451 if (errno || str == end || (end && *end))
452 goto err;
453
454 return num;
455 err:
456 if (errno == ERANGE)
457 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
458
459 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
460 }
461
462 long strtol_or_err(const char *str, const char *errmesg)
463 {
464 long num;
465 char *end = NULL;
466
467 errno = 0;
468 if (str == NULL || *str == '\0')
469 goto err;
470 num = strtol(str, &end, 10);
471
472 if (errno || str == end || (end && *end))
473 goto err;
474
475 return num;
476 err:
477 if (errno == ERANGE)
478 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
479
480 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
481 }
482
483 unsigned long strtoul_or_err(const char *str, const char *errmesg)
484 {
485 unsigned long num;
486 char *end = NULL;
487
488 errno = 0;
489 if (str == NULL || *str == '\0')
490 goto err;
491 num = strtoul(str, &end, 10);
492
493 if (errno || str == end || (end && *end))
494 goto err;
495
496 return num;
497 err:
498 if (errno == ERANGE)
499 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
500
501 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
502 }
503
504 uintmax_t strtosize_or_err(const char *str, const char *errmesg)
505 {
506 uintmax_t num;
507
508 if (strtosize(str, &num) == 0)
509 return num;
510
511 if (errno)
512 err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
513
514 errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str);
515 }
516
517
518 void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg)
519 {
520 double user_input;
521
522 user_input = strtod_or_err(str, errmesg);
523 tv->tv_sec = (time_t) user_input;
524 tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000);
525 }
526
527 /*
528 * Converts stat->st_mode to ls(1)-like mode string. The size of "str" must
529 * be 11 bytes.
530 */
531 char *xstrmode(mode_t mode, char *str)
532 {
533 unsigned short i = 0;
534
535 if (S_ISDIR(mode))
536 str[i++] = 'd';
537 else if (S_ISLNK(mode))
538 str[i++] = 'l';
539 else if (S_ISCHR(mode))
540 str[i++] = 'c';
541 else if (S_ISBLK(mode))
542 str[i++] = 'b';
543 else if (S_ISSOCK(mode))
544 str[i++] = 's';
545 else if (S_ISFIFO(mode))
546 str[i++] = 'p';
547 else if (S_ISREG(mode))
548 str[i++] = '-';
549
550 str[i++] = mode & S_IRUSR ? 'r' : '-';
551 str[i++] = mode & S_IWUSR ? 'w' : '-';
552 str[i++] = (mode & S_ISUID
553 ? (mode & S_IXUSR ? 's' : 'S')
554 : (mode & S_IXUSR ? 'x' : '-'));
555 str[i++] = mode & S_IRGRP ? 'r' : '-';
556 str[i++] = mode & S_IWGRP ? 'w' : '-';
557 str[i++] = (mode & S_ISGID
558 ? (mode & S_IXGRP ? 's' : 'S')
559 : (mode & S_IXGRP ? 'x' : '-'));
560 str[i++] = mode & S_IROTH ? 'r' : '-';
561 str[i++] = mode & S_IWOTH ? 'w' : '-';
562 str[i++] = (mode & S_ISVTX
563 ? (mode & S_IXOTH ? 't' : 'T')
564 : (mode & S_IXOTH ? 'x' : '-'));
565 str[i] = '\0';
566
567 return str;
568 }
569
570 /*
571 * returns exponent (2^x=n) in range KiB..EiB (2^10..2^60)
572 */
573 static int get_exp(uint64_t n)
574 {
575 int shft;
576
577 for (shft = 10; shft <= 60; shft += 10) {
578 if (n < (1ULL << shft))
579 break;
580 }
581 return shft - 10;
582 }
583
584 char *size_to_human_string(int options, uint64_t bytes)
585 {
586 char buf[32];
587 int dec, exp;
588 uint64_t frac;
589 const char *letters = "BKMGTPE";
590 char suffix[sizeof(" KiB")], *psuf = suffix;
591 char c;
592
593 if (options & SIZE_SUFFIX_SPACE)
594 *psuf++ = ' ';
595
596
597 exp = get_exp(bytes);
598 c = *(letters + (exp ? exp / 10 : 0));
599 dec = exp ? bytes / (1ULL << exp) : bytes;
600 frac = exp ? bytes % (1ULL << exp) : 0;
601
602 *psuf++ = c;
603
604 if ((options & SIZE_SUFFIX_3LETTER) && (c != 'B')) {
605 *psuf++ = 'i';
606 *psuf++ = 'B';
607 }
608
609 *psuf = '\0';
610
611 /* fprintf(stderr, "exp: %d, unit: %c, dec: %d, frac: %jd\n",
612 * exp, suffix[0], dec, frac);
613 */
614
615 /* round */
616 if (frac) {
617 /* get 3 digits after decimal point */
618 if (frac >= UINT64_MAX / 1000)
619 frac = ((frac / 1024) * 1000) / (1ULL << (exp - 10)) ;
620 else
621 frac = (frac * 1000) / (1ULL << (exp)) ;
622
623 if (options & SIZE_DECIMAL_2DIGITS) {
624 /* round 4/5 and keep 2 digits after decimal point */
625 frac = (frac + 5) / 10 ;
626 } else {
627 /* round 4/5 and keep 1 digit after decimal point */
628 frac = ((frac + 50) / 100) * 10 ;
629 }
630
631 /* rounding could have overflowed */
632 if (frac == 100) {
633 dec++;
634 frac = 0;
635 }
636 }
637
638 if (frac) {
639 struct lconv const *l = localeconv();
640 char *dp = l ? l->decimal_point : NULL;
641 int len;
642
643 if (!dp || !*dp)
644 dp = ".";
645
646 len = snprintf(buf, sizeof(buf), "%d%s%02" PRIu64, dec, dp, frac);
647 if (len > 0 && (size_t) len < sizeof(buf)) {
648 /* remove potential extraneous zero */
649 if (buf[len - 1] == '0')
650 buf[len--] = '\0';
651 /* append suffix */
652 xstrncpy(buf+len, suffix, sizeof(buf) - len);
653 } else
654 *buf = '\0'; /* snprintf error */
655 } else
656 snprintf(buf, sizeof(buf), "%d%s", dec, suffix);
657
658 return strdup(buf);
659 }
660
661 /*
662 * Parses comma delimited list to array with IDs, for example:
663 *
664 * "aaa,bbb,ccc" --> ary[0] = FOO_AAA;
665 * ary[1] = FOO_BBB;
666 * ary[3] = FOO_CCC;
667 *
668 * The function name2id() provides conversion from string to ID.
669 *
670 * Returns: >= 0 : number of items added to ary[]
671 * -1 : parse error or unknown item
672 * -2 : arysz reached
673 */
674 int string_to_idarray(const char *list, int ary[], size_t arysz,
675 int (name2id)(const char *, size_t))
676 {
677 const char *begin = NULL, *p;
678 size_t n = 0;
679
680 if (!list || !*list || !ary || !arysz || !name2id)
681 return -1;
682
683 for (p = list; p && *p; p++) {
684 const char *end = NULL;
685 int id;
686
687 if (n >= arysz)
688 return -2;
689 if (!begin)
690 begin = p; /* begin of the column name */
691 if (*p == ',')
692 end = p; /* terminate the name */
693 if (*(p + 1) == '\0')
694 end = p + 1; /* end of string */
695 if (!begin || !end)
696 continue;
697 if (end <= begin)
698 return -1;
699
700 id = name2id(begin, end - begin);
701 if (id == -1)
702 return -1;
703 ary[ n++ ] = id;
704 begin = NULL;
705 if (end && !*end)
706 break;
707 }
708 return n;
709 }
710
711 /*
712 * Parses the array like string_to_idarray but if format is "+aaa,bbb"
713 * it adds fields to array instead of replacing them.
714 */
715 int string_add_to_idarray(const char *list, int ary[], size_t arysz,
716 size_t *ary_pos, int (name2id)(const char *, size_t))
717 {
718 const char *list_add;
719 int r;
720
721 if (!list || !*list || !ary_pos || *ary_pos > arysz)
722 return -1;
723
724 if (list[0] == '+')
725 list_add = &list[1];
726 else {
727 list_add = list;
728 *ary_pos = 0;
729 }
730
731 r = string_to_idarray(list_add, &ary[*ary_pos], arysz - *ary_pos, name2id);
732 if (r > 0)
733 *ary_pos += r;
734 return r;
735 }
736
737 /*
738 * LIST ::= <item> [, <item>]
739 *
740 * The <item> is translated to 'id' by name2id() function and the 'id' is used
741 * as a position in the 'ary' bit array. It means that the 'id' has to be in
742 * range <0..N> where N < sizeof(ary) * NBBY.
743 *
744 * Returns: 0 on success, <0 on error.
745 */
746 int string_to_bitarray(const char *list,
747 char *ary,
748 int (*name2bit)(const char *, size_t))
749 {
750 const char *begin = NULL, *p;
751
752 if (!list || !name2bit || !ary)
753 return -EINVAL;
754
755 for (p = list; p && *p; p++) {
756 const char *end = NULL;
757 int bit;
758
759 if (!begin)
760 begin = p; /* begin of the level name */
761 if (*p == ',')
762 end = p; /* terminate the name */
763 if (*(p + 1) == '\0')
764 end = p + 1; /* end of string */
765 if (!begin || !end)
766 continue;
767 if (end <= begin)
768 return -1;
769
770 bit = name2bit(begin, end - begin);
771 if (bit < 0)
772 return bit;
773 setbit(ary, bit);
774 begin = NULL;
775 if (end && !*end)
776 break;
777 }
778 return 0;
779 }
780
781 /*
782 * LIST ::= <item> [, <item>]
783 *
784 * The <item> is translated to 'id' by name2flag() function and the flags is
785 * set to the 'mask'
786 *
787 * Returns: 0 on success, <0 on error.
788 */
789 int string_to_bitmask(const char *list,
790 unsigned long *mask,
791 long (*name2flag)(const char *, size_t))
792 {
793 const char *begin = NULL, *p;
794
795 if (!list || !name2flag || !mask)
796 return -EINVAL;
797
798 for (p = list; p && *p; p++) {
799 const char *end = NULL;
800 long flag;
801
802 if (!begin)
803 begin = p; /* begin of the level name */
804 if (*p == ',')
805 end = p; /* terminate the name */
806 if (*(p + 1) == '\0')
807 end = p + 1; /* end of string */
808 if (!begin || !end)
809 continue;
810 if (end <= begin)
811 return -1;
812
813 flag = name2flag(begin, end - begin);
814 if (flag < 0)
815 return flag; /* error */
816 *mask |= flag;
817 begin = NULL;
818 if (end && !*end)
819 break;
820 }
821 return 0;
822 }
823
824 /*
825 * Parse the lower and higher values in a string containing
826 * "lower:higher" or "lower-higher" format. Note that either
827 * the lower or the higher values may be missing, and the def
828 * value will be assigned to it by default.
829 *
830 * Returns: 0 on success, <0 on error.
831 */
832 int parse_range(const char *str, int *lower, int *upper, int def)
833 {
834 char *end = NULL;
835
836 if (!str)
837 return 0;
838
839 *upper = *lower = def;
840 errno = 0;
841
842 if (*str == ':') { /* <:N> */
843 str++;
844 *upper = strtol(str, &end, 10);
845 if (errno || !end || *end || end == str)
846 return -1;
847 } else {
848 *upper = *lower = strtol(str, &end, 10);
849 if (errno || !end || end == str)
850 return -1;
851
852 if (*end == ':' && !*(end + 1)) /* <M:> */
853 *upper = def;
854 else if (*end == '-' || *end == ':') { /* <M:N> <M-N> */
855 str = end + 1;
856 end = NULL;
857 errno = 0;
858 *upper = strtol(str, &end, 10);
859
860 if (errno || !end || *end || end == str)
861 return -1;
862 }
863 }
864 return 0;
865 }
866
867 static const char *next_path_segment(const char *str, size_t *sz)
868 {
869 const char *start, *p;
870
871 start = str;
872 *sz = 0;
873 while (start && *start == '/' && *(start + 1) == '/')
874 start++;
875
876 if (!start || !*start)
877 return NULL;
878
879 for (*sz = 1, p = start + 1; *p && *p != '/'; p++) {
880 (*sz)++;
881 }
882
883 return start;
884 }
885
886 int streq_paths(const char *a, const char *b)
887 {
888 while (a && b) {
889 size_t a_sz, b_sz;
890 const char *a_seg = next_path_segment(a, &a_sz);
891 const char *b_seg = next_path_segment(b, &b_sz);
892
893 /*
894 fprintf(stderr, "A>>>(%zu) '%s'\n", a_sz, a_seg);
895 fprintf(stderr, "B>>>(%zu) '%s'\n", b_sz, b_seg);
896 */
897
898 /* end of the path */
899 if (a_sz + b_sz == 0)
900 return 1;
901
902 /* ignore tailing slash */
903 if (a_sz + b_sz == 1 &&
904 ((a_seg && *a_seg == '/') || (b_seg && *b_seg == '/')))
905 return 1;
906
907 if (!a_seg || !b_seg)
908 break;
909 if (a_sz != b_sz || strncmp(a_seg, b_seg, a_sz) != 0)
910 break;
911
912 a = a_seg + a_sz;
913 b = b_seg + b_sz;
914 };
915
916 return 0;
917 }
918
919 char *strnappend(const char *s, const char *suffix, size_t b)
920 {
921 size_t a;
922 char *r;
923
924 if (!s && !suffix)
925 return strdup("");
926 if (!s)
927 return strndup(suffix, b);
928 if (!suffix)
929 return strdup(s);
930
931 assert(s);
932 assert(suffix);
933
934 a = strlen(s);
935 if (b > ((size_t) -1) - a)
936 return NULL;
937
938 r = malloc(a + b + 1);
939 if (!r)
940 return NULL;
941
942 memcpy(r, s, a);
943 memcpy(r + a, suffix, b);
944 r[a+b] = 0;
945
946 return r;
947 }
948
949 char *strappend(const char *s, const char *suffix)
950 {
951 return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
952 }
953
954 char *strfappend(const char *s, const char *format, ...)
955 {
956 va_list ap;
957 char *val, *res;
958 int sz;
959
960 va_start(ap, format);
961 sz = vasprintf(&val, format, ap);
962 va_end(ap);
963
964 if (sz < 0)
965 return NULL;
966
967 res = strnappend(s, val, sz);
968 free(val);
969 return res;
970 }
971
972 static size_t strcspn_escaped(const char *s, const char *reject)
973 {
974 int escaped = 0;
975 int n;
976
977 for (n=0; s[n]; n++) {
978 if (escaped)
979 escaped = 0;
980 else if (s[n] == '\\')
981 escaped = 1;
982 else if (strchr(reject, s[n]))
983 break;
984 }
985
986 /* if s ends in \, return index of previous char */
987 return n - escaped;
988 }
989
990 /* Split a string into words. */
991 const char *split(const char **state, size_t *l, const char *separator, int quoted)
992 {
993 const char *current;
994
995 current = *state;
996
997 if (!*current) {
998 assert(**state == '\0');
999 return NULL;
1000 }
1001
1002 current += strspn(current, separator);
1003 if (!*current) {
1004 *state = current;
1005 return NULL;
1006 }
1007
1008 if (quoted && strchr("\'\"", *current)) {
1009 char quotechars[2] = {*current, '\0'};
1010
1011 *l = strcspn_escaped(current + 1, quotechars);
1012 if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
1013 (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
1014 /* right quote missing or garbage at the end */
1015 *state = current;
1016 return NULL;
1017 }
1018 *state = current++ + *l + 2;
1019 } else if (quoted) {
1020 *l = strcspn_escaped(current, separator);
1021 if (current[*l] && !strchr(separator, current[*l])) {
1022 /* unfinished escape */
1023 *state = current;
1024 return NULL;
1025 }
1026 *state = current + *l;
1027 } else {
1028 *l = strcspn(current, separator);
1029 *state = current + *l;
1030 }
1031
1032 return current;
1033 }
1034
1035 /* Rewind file pointer forward to new line. */
1036 int skip_fline(FILE *fp)
1037 {
1038 int ch;
1039
1040 do {
1041 if ((ch = fgetc(fp)) == EOF)
1042 return 1;
1043 if (ch == '\n')
1044 return 0;
1045 } while (1);
1046 }
1047
1048 #ifdef TEST_PROGRAM_STRUTILS
1049 #include <stdio.h>
1050 #include "xalloc.h"
1051
1052 struct testS {
1053 char *name;
1054 char *value;
1055 };
1056
1057 static int test_strdup_to_member(int argc, char *argv[])
1058 {
1059 struct testS *xx;
1060
1061 if (argc < 3)
1062 return EXIT_FAILURE;
1063
1064 xx = calloc(1, sizeof(*xx));
1065 if (!xx)
1066 err_oom();
1067
1068 strdup_to_struct_member(xx, name, argv[1]);
1069 strdup_to_struct_member(xx, value, argv[2]);
1070
1071 if (strcmp(xx->name, argv[1]) != 0 &&
1072 strcmp(xx->value, argv[2]) != 0)
1073 errx(EXIT_FAILURE, "strdup_to_struct_member() failed");
1074
1075 printf("1: '%s', 2: '%s'\n", xx->name, xx->value);
1076
1077 free(xx->name);
1078 free(xx->value);
1079 free(xx);
1080 return EXIT_SUCCESS;
1081 }
1082
1083 static int test_strutils_sizes(int argc, char *argv[])
1084 {
1085 uintmax_t size = 0;
1086 char *hum1, *hum2, *hum3;
1087
1088 if (argc < 2)
1089 return EXIT_FAILURE;
1090
1091 if (strtosize(argv[1], &size))
1092 errx(EXIT_FAILURE, "invalid size '%s' value", argv[1]);
1093
1094 hum1 = size_to_human_string(SIZE_SUFFIX_1LETTER, size);
1095 hum2 = size_to_human_string(SIZE_SUFFIX_3LETTER |
1096 SIZE_SUFFIX_SPACE, size);
1097 hum3 = size_to_human_string(SIZE_SUFFIX_3LETTER |
1098 SIZE_SUFFIX_SPACE |
1099 SIZE_DECIMAL_2DIGITS, size);
1100
1101 printf("%25s : %20ju : %8s : %12s : %13s\n", argv[1], size, hum1, hum2, hum3);
1102 free(hum1);
1103 free(hum2);
1104 free(hum3);
1105
1106 return EXIT_SUCCESS;
1107 }
1108
1109 static int test_strutils_cmp_paths(int argc, char *argv[])
1110 {
1111 int rc = streq_paths(argv[1], argv[2]);
1112
1113 if (argc < 3)
1114 return EXIT_FAILURE;
1115
1116 printf("%s: '%s' '%s'\n", rc == 1 ? "YES" : "NOT", argv[1], argv[2]);
1117 return EXIT_SUCCESS;
1118 }
1119
1120 int main(int argc, char *argv[])
1121 {
1122 if (argc == 3 && strcmp(argv[1], "--size") == 0)
1123 return test_strutils_sizes(argc - 1, argv + 1);
1124
1125 if (argc == 4 && strcmp(argv[1], "--cmp-paths") == 0)
1126 return test_strutils_cmp_paths(argc - 1, argv + 1);
1127
1128 if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0)
1129 return test_strdup_to_member(argc - 1, argv + 1);
1130
1131 fprintf(stderr, "usage: %1$s --size <number>[suffix]\n"
1132 " %1$s --cmp-paths <path> <path>\n"
1133 " %1$s --strdup-member <str> <str>\n",
1134 argv[0]);
1135
1136 return EXIT_FAILURE;
1137 }
1138 #endif /* TEST_PROGRAM_STRUTILS */