summaryrefslogtreecommitdiffstats
path: root/src/utils/lib/strutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/lib/strutils.c')
-rw-r--r--src/utils/lib/strutils.c242
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);
}