From a0d37b69ef8f4362f606aacd673eedc292e78af7 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 2 Dec 2007 22:00:35 +0100 Subject: [PATCH] [MINOR] implement a time parsing function This new function accepts inputs in various default units, from the microsecond to the day. It detects suffixes after numbers and performs the appropriate conversions between the user's unit and the program's unit, considering a unit-less number in the default unit. --- include/common/standard.h | 18 +++++++++ src/standard.c | 78 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) 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: