From 236e47e55554310cc19b8c37c7b844d53a239f28 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 3 Nov 2011 21:10:27 +0000 Subject: [PATCH] implementing time and size parsers for #1875 --- src/include/gnunet_configuration_lib.h | 19 ++++ src/include/gnunet_strings_lib.h | 13 +++ src/util/configuration.c | 36 +++++-- src/util/strings.c | 126 +++++++++++++++++++++++++ src/util/test_configuration.c | 11 +++ src/util/test_configuration_data.conf | 1 + 6 files changed, 197 insertions(+), 9 deletions(-) diff --git a/src/include/gnunet_configuration_lib.h b/src/include/gnunet_configuration_lib.h index 7167d8bd6..f8f302a18 100644 --- a/src/include/gnunet_configuration_lib.h +++ b/src/include/gnunet_configuration_lib.h @@ -226,6 +226,23 @@ GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle struct GNUNET_TIME_Relative *time); + +/** + * Get a configuration value that should be a size in bytes. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param size set to the size in bytes as stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + unsigned long long *size); + + /** * Test if we have a value for a particular option * @@ -337,6 +354,7 @@ GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option); + /** * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR" * where either in the "PATHS" section or the environtment @@ -378,6 +396,7 @@ GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, const char *value); + /** * Remove a filename from a configuration value that * represents a list of filenames diff --git a/src/include/gnunet_strings_lib.h b/src/include/gnunet_strings_lib.h index 6413fb102..637d4f7de 100644 --- a/src/include/gnunet_strings_lib.h +++ b/src/include/gnunet_strings_lib.h @@ -50,6 +50,18 @@ extern "C" #include "gnunet_time_lib.h" +/** + * Convert a given fancy human-readable size to bytes. + * + * @param fancy_size human readable string (i.e. 1 MB) + * @param size set to the size in bytes + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, + unsigned long long *size); + + /** * Convert a given filesize into a fancy human-readable format. * @@ -85,6 +97,7 @@ GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset); char * GNUNET_STRINGS_filename_expand (const char *fil); + /** * Fill a buffer of the given size with * count 0-terminated strings (given as varargs). diff --git a/src/util/configuration.c b/src/util/configuration.c index a269ed036..ba3aa7f45 100644 --- a/src/util/configuration.c +++ b/src/util/configuration.c @@ -731,16 +731,34 @@ GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle e = findEntry (cfg, section, option); if (e == NULL) return GNUNET_SYSERR; - if ((0 == strcasecmp (e->val, "infinity")) || - (0 == strcasecmp (e->val, "forever"))) - { - *time = GNUNET_TIME_UNIT_FOREVER_REL; - return GNUNET_OK; - } - if (1 != SSCANF (e->val, "%llu", &num)) + + return GNUNET_STRINGS_fancy_time_to_relative (e->val, + time); +} + + +/** + * Get a configuration value that should be a size in bytes. + * + * @param cfg configuration to inspect + * @param section section of interest + * @param option option of interest + * @param size set to the size in bytes as stored in the configuration + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_CONFIGURATION_get_value_size (const struct GNUNET_CONFIGURATION_Handle + *cfg, const char *section, + const char *option, + unsigned long long *size) +{ + struct ConfigEntry *e; + + e = findEntry (cfg, section, option); + if (e == NULL) return GNUNET_SYSERR; - time->rel_value = (uint64_t) num; - return GNUNET_OK; + return GNUNET_STRINGS_fancy_size_to_bytes (e->val, + size); } diff --git a/src/util/strings.c b/src/util/strings.c index 9e9aac3b1..63ebfc1e2 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -170,6 +170,132 @@ GNUNET_STRINGS_byte_size_fancy (unsigned long long size) } +/** + * Convert a given fancy human-readable size to bytes. + * + * @param fancy_size human readable string (i.e. 1 MB) + * @param size set to the size in bytes + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_size_to_bytes (const char *fancy_size, + unsigned long long *size) +{ + struct { + const char *name; + unsigned long long value; + } table[] = { + { "B", 1 }, + { "KiB", 1024 }, + { "kB", 1000 }, + { "MiB", 1024 * 1024 }, + { "MB", 1000 * 1000 }, + { "GiB", 1024 * 1024 * 1024 }, + { "GB", 1000 * 1000 * 1000 }, + { "TiB", 1024LL * 1024LL * 1024LL * 1024LL }, + { "TB", 1000LL * 1000LL * 1000LL * 1024LL }, + { "PiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL }, + { "PB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL}, + { "EiB", 1024LL * 1024LL * 1024LL * 1024LL * 1024LL * 1024LL}, + { "EB", 1000LL * 1000LL * 1000LL * 1024LL * 1000LL * 1000LL }, + { NULL, 0 } + }; + unsigned long long ret; + char *in; + const char *tok; + unsigned long long last; + unsigned int i; + + ret = 0; + last = 0; + in = GNUNET_strdup (fancy_size); + for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) + { + fprintf (stderr, "%s - %llu %llu\n", tok, ret, last); + i=0; + while ( (table[i].name != NULL) && + (0 != strcasecmp (table[i].name, tok) ) ) + i++; + if (table[i].name != NULL) + last *= table[i].value; + else + { + ret += last; + last = 0; + if (1 != sscanf (tok, "%llu", &last)) + return GNUNET_SYSERR; /* expected number */ + } + } + ret += last; + *size = ret; + return GNUNET_OK; +} + + +/** + * Convert a given fancy human-readable time to our internal + * representation. + * + * @param fancy_size human readable string (i.e. 1 minute) + * @param rtime set to the relative time + * @return GNUNET_OK on success, GNUNET_SYSERR on error + */ +int +GNUNET_STRINGS_fancy_time_to_relative (const char *fancy_size, + struct GNUNET_TIME_Relative *rtime) +{ + struct { + const char *name; + unsigned long long value; + } table[] = { + { "ms", 1 }, + { "s", 1000 }, + { "\"", 1000 }, + { "min", 60 * 1000 }, + { "minutes", 60 * 1000 }, + { "'", 60 * 1000 }, + { "h", 60 * 60 * 1000 }, + { "d", 24 * 60 * 60 * 1000 }, + { "a", 31557600 /* year */ }, + { NULL, 0 } + }; + unsigned long long ret; + char *in; + const char *tok; + unsigned long long last; + unsigned int i; + + if ((0 == strcasecmp (fancy_size, "infinity")) || + (0 == strcasecmp (fancy_size, "forever"))) + { + *rtime = GNUNET_TIME_UNIT_FOREVER_REL; + return GNUNET_OK; + } + ret = 0; + last = 0; + in = GNUNET_strdup (fancy_size); + for (tok = strtok (in, " "); tok != NULL; tok = strtok (NULL, " ")) + { + i=0; + while ( (table[i].name != NULL) && + (0 != strcasecmp (table[i].name, tok) ) ) + i++; + if (table[i].name != NULL) + last *= table[i].value; + else + { + ret += last; + last = 0; + if (1 != sscanf (tok, "%llu", &last)) + return GNUNET_SYSERR; /* expected number */ + } + } + ret += last; + rtime->rel_value = (uint64_t) ret; + return GNUNET_OK; +} + + /** * Convert the len characters long character sequence * given in input that is in the given charset diff --git a/src/util/test_configuration.c b/src/util/test_configuration.c index 4a993923b..9deb4fc35 100644 --- a/src/util/test_configuration.c +++ b/src/util/test_configuration.c @@ -337,6 +337,17 @@ testConfig () } GNUNET_free (c); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_size (cfg, "last", "size", &l)) + { + GNUNET_break (0); + return 10; + } + if (l != 512 * 1024) + { + GNUNET_break (0); + return 11; + } return 0; } diff --git a/src/util/test_configuration_data.conf b/src/util/test_configuration_data.conf index c3452c381..517cbf0b0 100644 --- a/src/util/test_configuration_data.conf +++ b/src/util/test_configuration_data.conf @@ -19,6 +19,7 @@ five=42 test = $SUBST/world boom = "1 2 3 testing" trailing = YES +size = 512 KiB [FILENAMES] test = "/Hello /File\ Name /World" -- 2.25.1