diff --git a/include/common/standard.h b/include/common/standard.h index 0dde6db37..3f7bed96e 100644 --- a/include/common/standard.h +++ b/include/common/standard.h @@ -238,4 +238,22 @@ static inline void get_localtime(const time_t now, struct tm *tm) localtime_r(&now, tm); } +/* This function parses a time value optionally followed by a unit suffix among + * "d", "h", "m", "s", "ms" or "us". It converts the value into the unit + * expected by the caller. The computation does its best to avoid overflows. + * The value is returned in if everything is fine, and a NULL is returned + * by the function. In case of error, a pointer to the error is returned and + * is left untouched. + */ +extern const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags); + +/* unit flags to pass to parse_time_err */ +#define TIME_UNIT_US 0x0000 +#define TIME_UNIT_MS 0x0001 +#define TIME_UNIT_S 0x0002 +#define TIME_UNIT_MIN 0x0003 +#define TIME_UNIT_HOUR 0x0004 +#define TIME_UNIT_DAY 0x0005 +#define TIME_UNIT_MASK 0x0007 + #endif /* _COMMON_STANDARD_H */ diff --git a/src/standard.c b/src/standard.c index 07aa5e48d..40ad47e0c 100644 --- a/src/standard.c +++ b/src/standard.c @@ -496,6 +496,84 @@ int strl2llrc(const char *s, int len, long long *ret) return 0; } +/* This function parses a time value optionally followed by a unit suffix among + * "d", "h", "m", "s", "ms" or "us". It converts the value into the unit + * expected by the caller. The computation does its best to avoid overflows. + * The value is returned in if everything is fine, and a NULL is returned + * by the function. In case of error, a pointer to the error is returned and + * is left untouched. Values are automatically rounded up when needed. + */ +const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags) +{ + unsigned imult, idiv; + unsigned omult, odiv; + unsigned value; + + omult = odiv = 1; + + switch (unit_flags & TIME_UNIT_MASK) { + case TIME_UNIT_US: omult = 1000000; break; + case TIME_UNIT_MS: omult = 1000; break; + case TIME_UNIT_S: break; + case TIME_UNIT_MIN: odiv = 60; break; + case TIME_UNIT_HOUR: odiv = 3600; break; + case TIME_UNIT_DAY: odiv = 86400; break; + default: break; + } + + value = 0; + + while (1) { + unsigned int j; + + j = *text - '0'; + if (j > 9) + break; + text++; + value *= 10; + value += j; + } + + imult = idiv = 1; + switch (*text) { + case '\0': /* no unit = default unit */ + imult = omult = idiv = odiv = 1; + break; + case 's': /* second = unscaled unit */ + break; + case 'u': /* microsecond : "us" */ + if (text[1] == 's') { + idiv = 1000000; + text++; + } + break; + case 'm': /* millisecond : "ms" or minute: "m" */ + if (text[1] == 's') { + idiv = 1000; + text++; + } else + imult = 60; + break; + case 'h': /* hour : "h" */ + imult = 3600; + break; + case 'd': /* day : "d" */ + imult = 86400; + break; + default: + return text; + break; + } + + if (omult % idiv == 0) { omult /= idiv; idiv = 1; } + if (idiv % omult == 0) { idiv /= omult; omult = 1; } + if (imult % odiv == 0) { imult /= odiv; odiv = 1; } + if (odiv % imult == 0) { odiv /= imult; imult = 1; } + + value = (value * (imult * omult) + (idiv * odiv - 1)) / (idiv * odiv); + *ret = value; + return NULL; +} /* * Local variables: