]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-settings: Added settings_get_time_msecs()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 6 May 2016 18:43:04 +0000 (21:43 +0300)
committerGitLab <gitlab@git.dovecot.net>
Sat, 7 May 2016 16:26:07 +0000 (19:26 +0300)
src/lib-settings/Makefile.am
src/lib-settings/settings-parser.c
src/lib-settings/settings-parser.h
src/lib-settings/test-settings-parser.c [new file with mode: 0644]

index 829a84b4bfe65fdd8b59253879d734face310e53..5434e32b567f4aa7f8f444b09366a7d29bd01776 100644 (file)
@@ -1,7 +1,8 @@
 noinst_LTLIBRARIES = libsettings.la
 
 AM_CPPFLAGS = \
-       -I$(top_srcdir)/src/lib
+       -I$(top_srcdir)/src/lib \
+       -I$(top_srcdir)/src/lib-test
 
 libsettings_la_SOURCES = \
        settings.c \
@@ -13,3 +14,23 @@ headers = \
 
 pkginc_libdir=$(pkgincludedir)
 pkginc_lib_HEADERS = $(headers)
+
+test_programs = \
+       test-settings-parser
+
+noinst_PROGRAMS = $(test_programs)
+
+test_libs = \
+       libsettings.la \
+       ../lib-test/libtest.la \
+       ../lib/liblib.la
+
+test_settings_parser_SOURCES = test-settings-parser.c
+test_settings_parser_LDADD = $(test_libs)
+test_settings_parser_DEPENDENCIES = $(test_libs)
+
+check: check-am check-test
+check-test: all-am
+       for bin in $(test_programs); do \
+         if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+       done
index 62a37df5bafeb19dd007025c0470bd3b1235e2a2..537685908f433a8082ff1521f1658172fad28cc0 100644 (file)
@@ -350,10 +350,10 @@ get_octal(struct setting_parser_context *ctx, const char *value,
        return 0;
 }
 
-int settings_get_time(const char *str, unsigned int *secs_r,
-                     const char **error_r)
+static int settings_get_time_full(const char *str, unsigned int *interval_r,
+                                 bool milliseconds, const char **error_r)
 {
-       uintmax_t num, multiply = 1;
+       uintmax_t num, multiply = milliseconds ? 1000 : 1;
        const char *p;
 
        if (str_parse_uintmax(str, &num, &p) < 0) {
@@ -368,29 +368,47 @@ int settings_get_time(const char *str, unsigned int *secs_r,
        }
        switch (i_toupper(*p)) {
        case 'S':
-               multiply = 1;
+               multiply *= 1;
                if (strncasecmp(p, "secs", strlen(p)) == 0 ||
                    strncasecmp(p, "seconds", strlen(p)) == 0)
                        p = "";
                break;
        case 'M':
-               multiply = 60;
+               multiply *= 60;
                if (strncasecmp(p, "mins", strlen(p)) == 0 ||
                    strncasecmp(p, "minutes", strlen(p)) == 0)
                        p = "";
+               else if (strncasecmp(p, "msecs", strlen(p)) == 0 ||
+                        strncasecmp(p, "mseconds", strlen(p)) == 0 ||
+                        strncasecmp(p, "millisecs", strlen(p)) == 0 ||
+                        strncasecmp(p, "milliseconds", strlen(p)) == 0) {
+                       if (milliseconds || (num % 1000) == 0) {
+                               if (!milliseconds) {
+                                       /* allow ms also for seconds, as long
+                                          as it's divisible by seconds */
+                                       num /= 1000;
+                               }
+                               multiply = 1;
+                               p = "";
+                               break;
+                       }
+                       *error_r = t_strdup_printf(
+                               "Milliseconds not supported for this setting: %s", str);
+                       return -1;
+               }
                break;
        case 'H':
-               multiply = 60*60;
+               multiply *= 60*60;
                if (strncasecmp(p, "hours", strlen(p)) == 0)
                        p = "";
                break;
        case 'D':
-               multiply = 60*60*24;
+               multiply *= 60*60*24;
                if (strncasecmp(p, "days", strlen(p)) == 0)
                        p = "";
                break;
        case 'W':
-               multiply = 60*60*24*7;
+               multiply *= 60*60*24*7;
                if (strncasecmp(p, "weeks", strlen(p)) == 0)
                        p = "";
                break;
@@ -405,10 +423,22 @@ int settings_get_time(const char *str, unsigned int *secs_r,
                                       str, NULL);
                return -1;
        }
-       *secs_r = num * multiply;
+       *interval_r = num * multiply;
        return 0;
 }
 
+int settings_get_time(const char *str, unsigned int *secs_r,
+                     const char **error_r)
+{
+       return settings_get_time_full(str, secs_r, FALSE, error_r);
+}
+
+int settings_get_time_msecs(const char *str, unsigned int *msecs_r,
+                           const char **error_r)
+{
+       return settings_get_time_full(str, msecs_r, TRUE, error_r);
+}
+
 int settings_get_size(const char *str, uoff_t *bytes_r,
                      const char **error_r)
 {
index b68195a65f41b73111daf3c670bbac7034a7c3bb..03496ee29fb7fa0dac1a7d6d92a510727ef48926 100644 (file)
@@ -233,6 +233,9 @@ const char *settings_section_escape(const char *name);
 /* Parse time interval string, return as seconds. */
 int settings_get_time(const char *str, unsigned int *secs_r,
                      const char **error_r);
+/* Parse time interval string, return as milliseconds. */
+int settings_get_time_msecs(const char *str, unsigned int *msecs_r,
+                           const char **error_r);
 /* Parse size string, return as bytes. */
 int settings_get_size(const char *str, uoff_t *bytes_r,
                      const char **error_r);
diff --git a/src/lib-settings/test-settings-parser.c b/src/lib-settings/test-settings-parser.c
new file mode 100644 (file)
index 0000000..75d7d0a
--- /dev/null
@@ -0,0 +1,149 @@
+/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "settings-parser.h"
+#include "test-common.h"
+
+static void test_settings_get_time(void)
+{
+       struct {
+               const char *input;
+               unsigned int output;
+       } tests[] = {
+               { "0", 0 },
+
+               { "59s", 59 },
+               { "59 s", 59 },
+               { "59se", 59 },
+               { "59sec", 59 },
+               { "59secs", 59 },
+               { "59seco", 59 },
+               { "59secon", 59 },
+               { "59second", 59 },
+               { "59seconds", 59 },
+               { "123456   seconds", 123456 },
+
+               { "123m", 123*60 },
+               { "123 m", 123*60 },
+               { "123 mi", 123*60 },
+               { "123 min", 123*60 },
+               { "123 mins", 123*60 },
+               { "123 minu", 123*60 },
+               { "123 minut", 123*60 },
+               { "123 minute", 123*60 },
+               { "123 minutes", 123*60 },
+
+               { "123h", 123*60*60 },
+               { "123 h", 123*60*60 },
+               { "123 ho", 123*60*60 },
+               { "123 hou", 123*60*60 },
+               { "123 hour", 123*60*60 },
+               { "123 hours", 123*60*60 },
+
+               { "12d", 12*60*60*24 },
+               { "12 d", 12*60*60*24 },
+               { "12 da", 12*60*60*24 },
+               { "12 day", 12*60*60*24 },
+               { "12 days", 12*60*60*24 },
+
+               { "3w", 3*60*60*24*7 },
+               { "3 w", 3*60*60*24*7 },
+               { "3 we", 3*60*60*24*7 },
+               { "3 wee", 3*60*60*24*7 },
+               { "3 week", 3*60*60*24*7 },
+               { "3 weeks", 3*60*60*24*7 },
+
+               { "1000ms", 1 },
+               { "50000ms", 50 },
+       };
+       struct {
+               const char *input;
+               unsigned int output;
+       } msecs_tests[] = {
+               { "0ms", 0 },
+               { "1ms", 1 },
+               { "123456ms", 123456 },
+               { "123456 ms", 123456 },
+               { "123456mse", 123456 },
+               { "123456msec", 123456 },
+               { "123456msecs", 123456 },
+               { "123456mseco", 123456 },
+               { "123456msecon", 123456 },
+               { "123456msecond", 123456 },
+               { "123456mseconds", 123456 },
+               { "123456mil", 123456 },
+               { "123456mill", 123456 },
+               { "123456milli", 123456 },
+               { "123456millis", 123456 },
+               { "123456millisec", 123456 },
+               { "123456millisecs", 123456 },
+               { "123456milliseco", 123456 },
+               { "123456millisecon", 123456 },
+               { "123456millisecond", 123456 },
+               { "123456milliseconds", 123456 },
+               { "4294967295 ms", 4294967295 },
+       };
+       const char *secs_errors[] = {
+               "-1",
+               "1",
+               /* wrong spellings: */
+               "1ss",
+               "1secss",
+               "1secondss",
+               "1ma",
+               "1minsa",
+               "1hu",
+               "1hoursa",
+               "1dd",
+               "1days?",
+               "1wa",
+               "1weeksb",
+
+               /* milliseconds: */
+               "1ms",
+               "999ms",
+               "1001ms",
+               /* overflows: */
+               "7102 w",
+               "4294967296 s",
+       };
+       const char *msecs_errors[] = {
+               "-1",
+               "1",
+               /* wrong spellings: */
+               "1mis",
+               "1mss",
+               /* overflows: */
+               "8 w",
+               "4294967296 ms",
+       };
+       unsigned int i, secs, msecs;
+       const char *error;
+
+       test_begin("settings_get_time()");
+       for (i = 0; i < N_ELEMENTS(tests); i++) {
+               test_assert_idx(settings_get_time(tests[i].input, &secs, &error) == 0, i);
+               test_assert_idx(secs == tests[i].output, i);
+
+               test_assert_idx(settings_get_time_msecs(tests[i].input, &msecs, &error) == 0, i);
+               test_assert_idx(msecs == tests[i].output*1000, i);
+       }
+       for (i = 0; i < N_ELEMENTS(msecs_tests); i++) {
+               test_assert_idx(settings_get_time_msecs(msecs_tests[i].input, &msecs, &error) == 0, i);
+               test_assert_idx(msecs == msecs_tests[i].output, i);
+       }
+       for (i = 0; i < N_ELEMENTS(secs_errors); i++)
+               test_assert_idx(settings_get_time(secs_errors[i], &secs, &error) < 0, i);
+       for (i = 0; i < N_ELEMENTS(msecs_errors); i++)
+               test_assert_idx(settings_get_time_msecs(msecs_errors[i], &msecs, &error) < 0, i);
+       test_end();
+}
+
+int main(void)
+{
+       static void (*test_functions[])(void) = {
+               test_settings_get_time,
+               NULL
+       };
+       return test_run(test_functions);
+}