diff options
Diffstat (limited to 'src/utils/lib/strutils.c')
-rw-r--r-- | src/utils/lib/strutils.c | 242 |
1 files changed, 159 insertions, 83 deletions
diff --git a/src/utils/lib/strutils.c b/src/utils/lib/strutils.c index eec4cd5..096aaf5 100644 --- a/src/utils/lib/strutils.c +++ b/src/utils/lib/strutils.c @@ -319,103 +319,125 @@ char *strndup(const char *s, size_t n) } #endif -static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base); -static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base); - -int16_t strtos16_or_err(const char *str, const char *errmesg) +/* + * convert strings to numbers; returns <0 on error, and 0 on success + */ +int ul_strtos64(const char *str, int64_t *num, int base) { - int32_t num = strtos32_or_err(str, errmesg); + char *end = NULL; - if (num < INT16_MIN || num > INT16_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - } - return num; + errno = 0; + if (str == NULL || *str == '\0') + return -EINVAL; + *num = (int64_t) strtoimax(str, &end, base); + + if (errno || str == end || (end && *end)) + return -EINVAL; + return 0; } -static uint16_t _strtou16_or_err(const char *str, const char *errmesg, int base) +int ul_strtou64(const char *str, uint64_t *num, int base) { - uint32_t num = _strtou32_or_err(str, errmesg, base); + char *end = NULL; + int64_t tmp; - if (num > UINT16_MAX) { + errno = 0; + if (str == NULL || *str == '\0') + return -EINVAL; + + /* we need to ignore negative numbers, note that for invalid negative + * number strtoimax() returns negative number too, so we do not + * need to check errno here */ + tmp = (int64_t) strtoimax(str, &end, base); + if (tmp < 0) errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + else { + errno = 0; + *num = strtoumax(str, &end, base); } - return num; -} -uint16_t strtou16_or_err(const char *str, const char *errmesg) -{ - return _strtou16_or_err(str, errmesg, 10); + if (errno || str == end || (end && *end)) + return -EINVAL; + return 0; } -uint16_t strtox16_or_err(const char *str, const char *errmesg) +int ul_strtos32(const char *str, int32_t *num, int base) { - return _strtou16_or_err(str, errmesg, 16); + int64_t tmp; + int rc; + + rc = ul_strtos64(str, &tmp, base); + if (rc == 0 && (tmp < INT32_MIN || tmp > INT32_MAX)) + rc = -(errno = ERANGE); + if (rc == 0) + *num = (int32_t) tmp; + return rc; } -int32_t strtos32_or_err(const char *str, const char *errmesg) +int ul_strtou32(const char *str, uint32_t *num, int base) { - int64_t num = strtos64_or_err(str, errmesg); - - if (num < INT32_MIN || num > INT32_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - } - return num; + uint64_t tmp; + int rc; + + rc = ul_strtou64(str, &tmp, base); + if (rc == 0 && tmp > UINT32_MAX) + rc = -(errno = ERANGE); + if (rc == 0) + *num = (uint32_t) tmp; + return rc; } -static uint32_t _strtou32_or_err(const char *str, const char *errmesg, int base) +/* + * Covert strings to numbers in defined range and print message on error. + * + * These functions are used when we read input from users (getopt() etc.). It's + * better to consolidate the code and keep it all based on 64-bit numbers then + * implement it for 32 and 16-bit numbers too. + */ +int64_t str2num_or_err(const char *str, int base, const char *errmesg, + int64_t low, int64_t up) { - uint64_t num = _strtou64_or_err(str, errmesg, base); + int64_t num = 0; + int rc; - if (num > UINT32_MAX) { - errno = ERANGE; - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + rc = ul_strtos64(str, &num, base); + if (rc == 0 && ((low && num < low) || (up && num > up))) + rc = -(errno = ERANGE); + + if (rc) { + if (errno == ERANGE) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); } return num; } -uint32_t strtou32_or_err(const char *str, const char *errmesg) -{ - return _strtou32_or_err(str, errmesg, 10); -} - -uint32_t strtox32_or_err(const char *str, const char *errmesg) -{ - return _strtou32_or_err(str, errmesg, 16); -} - -int64_t strtos64_or_err(const char *str, const char *errmesg) +uint64_t str2unum_or_err(const char *str, int base, const char *errmesg, uint64_t up) { - int64_t num; - char *end = NULL; - - errno = 0; - if (str == NULL || *str == '\0') - goto err; - num = strtoimax(str, &end, 10); + uint64_t num = 0; + int rc; - if (errno || str == end || (end && *end)) - goto err; + rc = ul_strtou64(str, &num, base); + if (rc == 0 && (up && num > up)) + rc = -(errno = ERANGE); + if (rc) { + if (errno == ERANGE) + err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); + } return num; -err: - if (errno == ERANGE) - err(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); - - errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); } -static uint64_t _strtou64_or_err(const char *str, const char *errmesg, int base) +double strtod_or_err(const char *str, const char *errmesg) { - uintmax_t num; + double num; char *end = NULL; errno = 0; if (str == NULL || *str == '\0') goto err; - num = strtoumax(str, &end, base); + num = strtod(str, &end); if (errno || str == end || (end && *end)) goto err; @@ -428,17 +450,7 @@ err: errx(STRTOXX_EXIT_CODE, "%s: '%s'", errmesg, str); } -uint64_t strtou64_or_err(const char *str, const char *errmesg) -{ - return _strtou64_or_err(str, errmesg, 10); -} - -uint64_t strtox64_or_err(const char *str, const char *errmesg) -{ - return _strtou64_or_err(str, errmesg, 16); -} - -double strtod_or_err(const char *str, const char *errmesg) +long double strtold_or_err(const char *str, const char *errmesg) { double num; char *end = NULL; @@ -446,7 +458,7 @@ double strtod_or_err(const char *str, const char *errmesg) errno = 0; if (str == NULL || *str == '\0') goto err; - num = strtod(str, &end); + num = strtold(str, &end); if (errno || str == end || (end && *end)) goto err; @@ -517,11 +529,19 @@ uintmax_t strtosize_or_err(const char *str, const char *errmesg) void strtotimeval_or_err(const char *str, struct timeval *tv, const char *errmesg) { - double user_input; + long double user_input; - user_input = strtod_or_err(str, errmesg); + user_input = strtold_or_err(str, errmesg); tv->tv_sec = (time_t) user_input; - tv->tv_usec = (long)((user_input - tv->tv_sec) * 1000000); + tv->tv_usec = (suseconds_t)((user_input - tv->tv_sec) * 1000000); +} + +time_t strtotime_or_err(const char *str, const char *errmesg) +{ + int64_t user_input; + + user_input = strtos64_or_err(str, errmesg); + return (time_t) user_input; } /* @@ -1045,6 +1065,36 @@ int skip_fline(FILE *fp) } while (1); } + +/* compare two strings, but ignoring non-alnum and case of the characters, for example + * "Hello (123)!" is the same as "hello123". + */ +int ul_stralnumcmp(const char *p1, const char *p2) +{ + const unsigned char *s1 = (const unsigned char *) p1; + const unsigned char *s2 = (const unsigned char *) p2; + unsigned char c1, c2; + + do { + do { + c1 = (unsigned char) *s1++; + } while (c1 != '\0' && !isalnum((unsigned int) c1)); + + do { + c2 = (unsigned char) *s2++; + } while (c2 != '\0' && !isalnum((unsigned int) c2)); + + if (c1 != '\0') + c1 = tolower(c1); + if (c2 != '\0') + c2 = tolower(c2); + if (c1 == '\0') + return c1 - c2; + } while (c1 == c2); + + return c1 - c2; +} + #ifdef TEST_PROGRAM_STRUTILS struct testS { char *name; @@ -1133,23 +1183,49 @@ static int test_strutils_normalize(int argc, char *argv[]) int main(int argc, char *argv[]) { - if (argc == 3 && strcmp(argv[1], "--size") == 0) + if (argc == 3 && strcmp(argv[1], "--size") == 0) { return test_strutils_sizes(argc - 1, argv + 1); - if (argc == 4 && strcmp(argv[1], "--cmp-paths") == 0) + } else if (argc == 4 && strcmp(argv[1], "--cmp-paths") == 0) { return test_strutils_cmp_paths(argc - 1, argv + 1); - if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0) + } else if (argc == 4 && strcmp(argv[1], "--strdup-member") == 0) { return test_strdup_to_member(argc - 1, argv + 1); - else if (argc == 3 && strcmp(argv[1], "--normalize") == 0) + } else if (argc == 4 && strcmp(argv[1], "--stralnumcmp") == 0) { + printf("%s\n", ul_stralnumcmp(argv[2], argv[3]) == 0 ? + "match" : "dismatch"); + return EXIT_SUCCESS; + } else if (argc == 3 && strcmp(argv[1], "--normalize") == 0) { return test_strutils_normalize(argc - 1, argv + 1); - else { + + } else if (argc == 3 && strcmp(argv[1], "--strtos64") == 0) { + printf("'%s'-->%jd\n", argv[2], strtos64_or_err(argv[2], "strtos64 failed")); + return EXIT_SUCCESS; + } else if (argc == 3 && strcmp(argv[1], "--strtou64") == 0) { + printf("'%s'-->%ju\n", argv[2], strtou64_or_err(argv[2], "strtou64 failed")); + return EXIT_SUCCESS; + } else if (argc == 3 && strcmp(argv[1], "--strtos32") == 0) { + printf("'%s'-->%d\n", argv[2], strtos32_or_err(argv[2], "strtos32 failed")); + return EXIT_SUCCESS; + } else if (argc == 3 && strcmp(argv[1], "--strtou32") == 0) { + printf("'%s'-->%u\n", argv[2], strtou32_or_err(argv[2], "strtou32 failed")); + return EXIT_SUCCESS; + } else if (argc == 3 && strcmp(argv[1], "--strtos16") == 0) { + printf("'%s'-->%hd\n", argv[2], strtos16_or_err(argv[2], "strtos16 failed")); + return EXIT_SUCCESS; + } else if (argc == 3 && strcmp(argv[1], "--strtou16") == 0) { + printf("'%s'-->%hu\n", argv[2], strtou16_or_err(argv[2], "strtou16 failed")); + return EXIT_SUCCESS; + + } else { fprintf(stderr, "usage: %1$s --size <number>[suffix]\n" " %1$s --cmp-paths <path> <path>\n" " %1$s --strdup-member <str> <str>\n" - " %1$s --normalize <str>\n", + " %1$s --stralnumcmp <str> <str>\n" + " %1$s --normalize <str>\n" + " %1$s --strto{s,u}{16,32,64} <str>\n", argv[0]); exit(EXIT_FAILURE); } |