diff --git a/src/optparse.c b/src/optparse.c deleted file mode 100644 index 867b635..0000000 --- a/src/optparse.c +++ /dev/null @@ -1,391 +0,0 @@ -/** @file - Option parsing functions to complement getopt. - - Copyright (C) 2017 Christian Zuckschwerdt - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. -*/ - -#include "optparse.h" -#include -#include -#include -#include - -int atobv(char *arg, int def) -{ - if (!arg) - return def; - if (!strcasecmp(arg, "true") || !strcasecmp(arg, "yes") || !strcasecmp(arg, "on") || !strcasecmp(arg, "enable")) - return 1; - return atoi(arg); -} - -int atoiv(char *arg, int def) -{ - if (!arg) - return def; - char *endptr; - int val = strtol(arg, &endptr, 10); - if (arg == endptr) - return def; - return val; -} - -char *arg_param(char *arg) -{ - if (!arg) - return NULL; - char *p = strchr(arg, ':'); - char *c = strchr(arg, ','); - if (p && (!c || p < c)) - return ++p; - else if (c) - return c; - else - return p; -} - -double arg_float(const char *str, const char *error_hint) -{ - if (!str) { - fprintf(stderr, "%smissing number argument\n", error_hint); - exit(1); - } - - if (!*str) { - fprintf(stderr, "%sempty number argument\n", error_hint); - exit(1); - } - - // allow whitespace and equals char - while (*str == ' ' || *str == '=') - ++str; - - char *endptr; - double val = strtod(str, &endptr); - - if (str == endptr) { - fprintf(stderr, "%sinvalid number argument (%s)\n", error_hint, str); - exit(1); - } - - return val; -} - -char *hostport_param(char *param, char **host, char **port) -{ - if (param && *param) { - if (param[0] == '/' && param[1] == '/') { - param += 2; - } - if (*param != ':' && *param != ',') { - *host = param; - if (*param == '[') { - (*host)++; - param = strchr(param, ']'); - if (param) { - *param++ = '\0'; - } - else { - fprintf(stderr, "Malformed Ipv6 address!\n"); - exit(1); - } - } - } - char *colon = strchr(param, ':'); - char *comma = strchr(param, ','); - if (colon && (!comma || colon < comma)) { - *colon++ = '\0'; - *port = colon; - } - if (comma) { - *comma++ = '\0'; - return comma; - } - } - return NULL; -} - -uint32_t atouint32_metric(const char *str, const char *error_hint) -{ - if (!str) { - fprintf(stderr, "%smissing number argument\n", error_hint); - exit(1); - } - - if (!*str) { - fprintf(stderr, "%sempty number argument\n", error_hint); - exit(1); - } - - char *endptr; - double val = strtod(str, &endptr); - - if (str == endptr) { - fprintf(stderr, "%sinvalid number argument (%s)\n", error_hint, str); - exit(1); - } - - if (val < 0.0) { - fprintf(stderr, "%snon-negative number argument expected (%f)\n", error_hint, val); - exit(1); - } - - // allow whitespace before suffix - while (*endptr == ' ' || *endptr == '\t') - ++endptr; - - switch (*endptr) { - case '\0': - break; - case 'k': - case 'K': - val *= 1e3; - break; - case 'M': - case 'm': - val *= 1e6; - break; - case 'G': - case 'g': - val *= 1e9; - break; - default: - fprintf(stderr, "%sunknown number suffix (%s)\n", error_hint, endptr); - exit(1); - } - - if (val > UINT32_MAX) { - fprintf(stderr, "%snumber argument too big (%f)\n", error_hint, val); - exit(1); - } - - val += 1e-5; // rounding (e.g. 4123456789.99999) - if (val - (uint32_t)val > 2e-5) { - fprintf(stderr, "%sdecimal fraction (%f) did you forget k, M, or G suffix?\n", error_hint, val - (uint32_t)val); - } - - return (uint32_t)val; -} - -int atoi_time(const char *str, const char *error_hint) -{ - if (!str) { - fprintf(stderr, "%smissing time argument\n", error_hint); - exit(1); - } - - if (!*str) { - fprintf(stderr, "%sempty time argument\n", error_hint); - exit(1); - } - - char *endptr = NULL; - double val = 0.0; - unsigned colons = 0; - - do { - double num = strtod(str, &endptr); - - if (!endptr || str == endptr) { - fprintf(stderr, "%sinvalid time argument (%s)\n", error_hint, str); - exit(1); - } - - // allow whitespace before suffix - while (*endptr == ' ' || *endptr == '\t') - ++endptr; - - switch (*endptr) { - case '\0': - if (colons == 0) { - // assume seconds - val += num; - break; - } - // intentional fallthrough - case ':': - ++colons; - if (colons == 1) - val += num * 60 * 60; - else if (colons == 2) - val += num * 60; - else if (colons == 3) - val += num; - else { - fprintf(stderr, "%stoo many colons (use HH:MM[:SS]))\n", error_hint); - exit(1); - } - if (*endptr) - ++endptr; - break; - case 's': - case 'S': - val += num; - ++endptr; - break; - case 'm': - case 'M': - val += num * 60; - ++endptr; - break; - case 'h': - case 'H': - val += num * 60 * 60; - ++endptr; - break; - case 'd': - case 'D': - val += num * 60 * 60 * 24; - ++endptr; - break; - default: - fprintf(stderr, "%sunknown time suffix (%s)\n", error_hint, endptr); - exit(1); - } - - // chew up any remaining whitespace - while (*endptr == ' ' || *endptr == '\t') - ++endptr; - str = endptr; - - } while (*endptr); - - if (val > INT_MAX || val < INT_MIN) { - fprintf(stderr, "%stime argument too big (%f)\n", error_hint, val); - exit(1); - } - - if (val < 0) { - val -= 1e-5; // rounding (e.g. -4123456789.99999) - } - else { - val += 1e-5; // rounding (e.g. 4123456789.99999) - } - if (val - (int)(val) > 2e-5) { - fprintf(stderr, "%sdecimal fraction (%f) did you forget m, or h suffix?\n", error_hint, val - (uint32_t)val); - } - - return (int)val; -} - -char *asepc(char **stringp, char delim) -{ - if (!stringp || !*stringp) return NULL; - char *s = strchr(*stringp, delim); - if (s) *s++ = '\0'; - char *p = *stringp; - *stringp = s; - return p; -} - -char *getkwargs(char **s, char **key, char **val) -{ - char *v = asepc(s, ','); - char *k = asepc(&v, '='); - if (key) *key = k; - if (val) *val = v; - return k; -} - -char *trim_ws(char *str) -{ - if (!str || !*str) - return str; - while (*str == ' ' || *str == '\t' || *str == '\r' || *str == '\n') - ++str; - char *e = str; // end pointer (last non ws) - char *p = str; // scanning pointer - while (*p) { - while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') - ++p; - if (*p) - e = p++; - } - *++e = '\0'; - return str; -} - -char *remove_ws(char *str) -{ - if (!str) - return str; - char *d = str; // dst pointer - char *s = str; // src pointer - while (*s) { - while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n') - ++s; - if (*s) - *d++ = *s++; - } - *d++ = '\0'; - return str; -} - -// Unit testing -#ifdef _TEST -#define ASSERT_EQUALS(a,b) \ - do { \ - if ((a) == (b)) \ - ++passed; \ - else { \ - ++failed; \ - fprintf(stderr, "FAIL: %d <> %d\n", (a), (b)); \ - } \ - } while (0) - -int main(void) -{ - unsigned passed = 0; - unsigned failed = 0; - - fprintf(stderr, "optparse:: atouint32_metric\n"); - ASSERT_EQUALS(atouint32_metric("0", ""), 0); - ASSERT_EQUALS(atouint32_metric("1", ""), 1); - ASSERT_EQUALS(atouint32_metric("0.0", ""), 0); - ASSERT_EQUALS(atouint32_metric("1.0", ""), 1); - ASSERT_EQUALS(atouint32_metric("1.024k", ""), 1024); - ASSERT_EQUALS(atouint32_metric("433.92M", ""), 433920000); - ASSERT_EQUALS(atouint32_metric("433.94M", ""), 433940000); - ASSERT_EQUALS(atouint32_metric(" +1 G ", ""), 1000000000); - ASSERT_EQUALS(atouint32_metric("1e6", ""), 1000000); - - fprintf(stderr, "optparse:: atoi_time\n"); - ASSERT_EQUALS(atoi_time("0", ""), 0); - ASSERT_EQUALS(atoi_time("1", ""), 1); - ASSERT_EQUALS(atoi_time("0.0", ""), 0); - ASSERT_EQUALS(atoi_time("1.0", ""), 1); - ASSERT_EQUALS(atoi_time("1s", ""), 1); - ASSERT_EQUALS(atoi_time("2d", ""), 2 * 60 * 60 * 24); - ASSERT_EQUALS(atoi_time("2h", ""), 2 * 60 * 60); - ASSERT_EQUALS(atoi_time("2m", ""), 2 * 60); - ASSERT_EQUALS(atoi_time("2s", ""), 2); - ASSERT_EQUALS(atoi_time("2D", ""), 2 * 60 * 60 * 24); - ASSERT_EQUALS(atoi_time("2H", ""), 2 * 60 * 60); - ASSERT_EQUALS(atoi_time("2M", ""), 2 * 60); - ASSERT_EQUALS(atoi_time("2S", ""), 2); - ASSERT_EQUALS(atoi_time("2h3m4s", ""), 2 * 60 * 60 + 3 * 60 + 4); - ASSERT_EQUALS(atoi_time("2h 3m 4s", ""), 2 * 60 * 60 + 3 * 60 + 4); - ASSERT_EQUALS(atoi_time("2h3h 3m 4s 5", ""), 5 * 60 * 60 + 3 * 60 + 9); - ASSERT_EQUALS(atoi_time(" 2m ", ""), 2 * 60); - ASSERT_EQUALS(atoi_time("2 m", ""), 2 * 60); - ASSERT_EQUALS(atoi_time(" 2 m ", ""), 2 * 60); - ASSERT_EQUALS(atoi_time("-1m", ""), -60); - ASSERT_EQUALS(atoi_time("1h-15m", ""), 45 * 60); - - ASSERT_EQUALS(atoi_time("2:3", ""), 2 * 60 * 60 + 3 * 60); - ASSERT_EQUALS(atoi_time("2:3:4", ""), 2 * 60 * 60 + 3 * 60 + 4); - ASSERT_EQUALS(atoi_time("02:03", ""), 2 * 60 * 60 + 3 * 60); - ASSERT_EQUALS(atoi_time("02:03:04", ""), 2 * 60 * 60 + 3 * 60 + 4); - ASSERT_EQUALS(atoi_time(" 2 : 3 ", ""), 2 * 60 * 60 + 3 * 60); - ASSERT_EQUALS(atoi_time(" 2 : 3 : 4 ", ""), 2 * 60 * 60 + 3 * 60 + 4); - - fprintf(stderr, "optparse:: test (%u/%u) passed, (%u) failed.\n", passed, passed + failed, failed); - - return failed; -} -#endif /* _TEST */ diff --git a/src/optparse.h b/src/optparse.h deleted file mode 100644 index 6325693..0000000 --- a/src/optparse.h +++ /dev/null @@ -1,105 +0,0 @@ -/** @file - Option parsing functions to complement getopt. - - Copyright (C) 2017 Christian Zuckschwerdt - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. -*/ - -#ifndef INCLUDE_OPTPARSE_H_ -#define INCLUDE_OPTPARSE_H_ - -#include - -// makes strcasecmp() and strncasecmp() available when including optparse.h -#ifdef _MSC_VER - #include - #define strcasecmp(s1,s2) _stricmp(s1,s2) - #define strncasecmp(s1,s2,n) _strnicmp(s1,s2,n) -#else - #include -#endif - -/// Convert string to bool with fallback default. -/// Parses "true", "yes", "on", "enable" (not case-sensitive) to 1, atoi() otherwise. -int atobv(char *arg, int def); - -/// Convert string to int with fallback default. -int atoiv(char *arg, int def); - -/// Get the next colon or comma separated arg, NULL otherwise. -/// Returns string including comma if a comma is found first, -/// otherwise string after colon if found, NULL otherwise. -char *arg_param(char *arg); - -/// Convert a string with optional leading equals char to a double. -/// -/// Parse errors will fprintf(stderr, ...) and exit(1). -/// -/// @param str character string to parse -/// @param error_hint prepended to error output -/// @return parsed number value -double arg_float(const char *str, const char *error_hint); - -/// Parse param string to host and port. -/// E.g. ":514", "localhost", "[::1]", "127.0.0.1:514", "[::1]:514", -/// also "//localhost", "//localhost:514", "//:514". -/// Host or port are terminated at a comma, if found. -/// @return the remaining options -char *hostport_param(char *param, char **host, char **port); - -/// Convert a string to an unsigned integer, uses strtod() and accepts -/// metric suffixes of 'k', 'M', and 'G' (also 'K', 'm', and 'g'). -/// -/// Parse errors will fprintf(stderr, ...) and exit(1). -/// -/// @param str character string to parse -/// @param error_hint prepended to error output -/// @return parsed number value -uint32_t atouint32_metric(const char *str, const char *error_hint); - -/// Convert a string to an integer, uses strtod() and accepts -/// time suffixes of 'd', 'h', 'm', and 's' (also 'D', 'H', 'M', and 'S'), -/// or the form hours:minutes[:seconds]. -/// -/// Parse errors will fprintf(stderr, ...) and exit(1). -/// -/// @param str character string to parse -/// @param error_hint prepended to error output -/// @return parsed number value -int atoi_time(const char *str, const char *error_hint); - -/// Similar to strsep. -/// -/// @param[in,out] stringp String to parse inplace -/// @param delim the delimiter character -/// @return the original value of *stringp -char *asepc(char **stringp, char delim); - -/// Parse a comma-separated list of key/value pairs into kwargs. -/// -/// The input string will be modified and the pointer advanced. -/// The key and val pointers will be into the original string. -/// -/// @param[in,out] s String of key=value pairs, separated by commas -/// @param[out] key keyword argument if found, NULL otherwise -/// @param[out] val value if found, NULL otherwise -/// @return the original value of *stringp (the keyword found) -char *getkwargs(char **s, char **key, char **val); - -/// Trim left and right whitespace in string. -/// -/// @param[in,out] str String to change inplace -/// @return the trimmed value of str -char *trim_ws(char *str); - -/// Remove all whitespace from string. -/// -/// @param[in,out] str String to change inplace -/// @return the stripped value of str -char *remove_ws(char *str); - -#endif /* INCLUDE_OPTPARSE_H_ */