]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add substr parser from time deltas
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 28 Oct 2021 22:00:40 +0000 (18:00 -0400)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 28 Oct 2021 22:00:40 +0000 (18:00 -0400)
12 files changed:
src/bin/dhcpclient.c
src/bin/radclient.c
src/bin/radsnmp.c
src/lib/server/cf_parse.c
src/lib/unlang/compile.c
src/lib/util/sbuff.c
src/lib/util/sbuff.h
src/lib/util/time.c
src/lib/util/time.h
src/lib/util/value.c
src/modules/proto_ldap_sync/sync_touch.c
src/tests/unit/data_types.txt

index 8596e3781cba9e5aac1fed34393e5e7990fa9149..b793133a87ed9b5fe90ae7274e8dd60b14e43289 100644 (file)
@@ -608,7 +608,7 @@ int main(int argc, char **argv)
                        break;
 
                case 't':
-                       if (fr_time_delta_from_str(&timeout, optarg, FR_TIME_RES_SEC) < 0) usage();
+                       if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) usage();
                        break;
 
                case 'v':
index 2e4977bdd787da51b7659a2c8d6a540b53aacc99..4fb7d49b1e3ec1c1d7258875ac9220e239d15a02 100644 (file)
@@ -1315,7 +1315,7 @@ int main(int argc, char **argv)
                       break;
 
                case 't':
-                       if (fr_time_delta_from_str(&timeout, optarg, FR_TIME_RES_SEC) < 0) {
+                       if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
                                fr_perror("Failed parsing timeout value");
                                fr_exit_now(EXIT_FAILURE);
                        }
index 92beb9fb9afa0172234f418ac1efb982c6de2980..53b5038a30ec8b3f8fb642144e5b526616a0fff2 100644 (file)
@@ -1013,7 +1013,7 @@ int main(int argc, char **argv)
                       break;
 
                case 't':
-                       if (fr_time_delta_from_str(&conf->timeout, optarg, FR_TIME_RES_SEC) < 0) {
+                       if (fr_time_delta_from_str(&conf->timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
                                fr_perror("Failed parsing timeout value");
                                fr_exit_now(EXIT_FAILURE);
                        }
index b374e48ccbbe1d120ef50411d172cfd9b32b5e51..99dd53d41f9a1ea617cbb711ed42edf8ed539e6e 100644 (file)
@@ -483,7 +483,7 @@ int cf_pair_parse_value(TALLOC_CTX *ctx, void *out, UNUSED void *base, CONF_ITEM
        {
                fr_time_delta_t delta;
 
-               if (fr_time_delta_from_str(&delta, cp->value, FR_TIME_RES_SEC) < 0) {
+               if (fr_time_delta_from_str(&delta, cp->value, strlen(cp->value), FR_TIME_RES_SEC) < 0) {
                        cf_log_perr(cp, "Failed parsing config item");
                        goto error;
                }
index 42c918a5323241d383964a443303ee1b35efc8d2..f734cc247e500e384eee2f19aed4994349cd2a49 100644 (file)
@@ -1574,7 +1574,7 @@ static bool compile_retry_section(unlang_actions_t *actions, CONF_ITEM *ci)
                 *      magical reasons.
                 */
                if (strcmp(name, "initial_rtx_time") == 0) {
-                       if (fr_time_delta_from_str(&actions->retry.irt, value, FR_TIME_RES_SEC) < 0) {
+                       if (fr_time_delta_from_str(&actions->retry.irt, value, strlen(value), FR_TIME_RES_SEC) < 0) {
                        error:
                                cf_log_err(csi, "Failed parsing '%s = %s' - %s",
                                           name, value, fr_strerror());
@@ -1582,7 +1582,7 @@ static bool compile_retry_section(unlang_actions_t *actions, CONF_ITEM *ci)
                        }
 
                } else if (strcmp(name, "max_rtx_time") == 0) {
-                       if (fr_time_delta_from_str(&actions->retry.mrt, value, FR_TIME_RES_SEC) < 0) goto error;
+                       if (fr_time_delta_from_str(&actions->retry.mrt, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
 
                } else if (strcmp(name, "max_rtx_count") == 0) {
                        unsigned long v = strtoul(value, 0, 0);
@@ -1596,7 +1596,7 @@ static bool compile_retry_section(unlang_actions_t *actions, CONF_ITEM *ci)
                        actions->retry.mrc = v;
 
                } else if (strcmp(name, "max_rtx_duration") == 0) {
-                       if (fr_time_delta_from_str(&actions->retry.mrd, value, FR_TIME_RES_SEC) < 0) goto error;
+                       if (fr_time_delta_from_str(&actions->retry.mrd, value, strlen(value), FR_TIME_RES_SEC) < 0) goto error;
                } else {
                        cf_log_err(csi, "Invalid item '%s' in 'retry' configuration.", name);
                        return false;
index 33cc3fd3b917b3ca6ac466063860177b34c38919..6b55971e0db29fc5254b8cadd375c4ea4da26229 100644 (file)
@@ -64,6 +64,10 @@ bool const sbuff_char_class_float[UINT8_MAX + 1] = {
        ['-'] = true, ['+'] = true, ['e'] = true, ['E'] = true, ['.'] = true,
 };
 
+bool const sbuff_char_class_zero[UINT8_MAX + 1] = {
+       ['0'] = true
+};
+
 bool const sbuff_char_class_hex[UINT8_MAX + 1] = { SBUFF_CHAR_CLASS_HEX };
 bool const sbuff_char_alpha_num[UINT8_MAX + 1] = { SBUFF_CHAR_CLASS_ALPHA_NUM };
 bool const sbuff_char_whitespace[UINT8_MAX + 1] = {
index f0f068aaa7102aa22bbfdacb04063bf1a40e5e48..6d3ae09b3354f66b61f309b97e3b2daed4138061 100644 (file)
@@ -259,6 +259,7 @@ typedef enum {
 extern bool const sbuff_char_class_uint[UINT8_MAX + 1];
 extern bool const sbuff_char_class_int[UINT8_MAX + 1];
 extern bool const sbuff_char_class_float[UINT8_MAX + 1];
+extern bool const sbuff_char_class_zero[UINT8_MAX + 1];
 extern bool const sbuff_char_class_hex[UINT8_MAX + 1];
 extern bool const sbuff_char_alpha_num[UINT8_MAX + 1];
 extern bool const sbuff_char_whitespace[UINT8_MAX + 1];
@@ -1549,6 +1550,8 @@ size_t    fr_sbuff_adv_past_strcase(fr_sbuff_t *sbuff, char const *needle, size_t n
 size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len,
                                  bool const allowed[static UINT8_MAX + 1], fr_sbuff_term_t const *tt);
 
+#define fr_sbuff_adv_past_zeros(_sbuff, _len, _tt) fr_sbuff_adv_past_allowed(_sbuff, _len, sbuff_char_class_zero, _tt)
+
 #define fr_sbuff_adv_past_whitespace(_sbuff, _len, _tt) fr_sbuff_adv_past_allowed(_sbuff, _len, sbuff_char_whitespace, _tt)
 
 #define fr_sbuff_adv_past_blank(_sbuff, _len, _tt) fr_sbuff_adv_past_allowed(_sbuff, _len, sbuff_char_blank, _tt)
index aeb5377d1f57a18206c50b2f938a9dc92c0acfa5..3d55a5c68b7d51ca5819852f4441bfb6e773497d 100644 (file)
@@ -55,7 +55,7 @@ int64_t const fr_time_multiplier_by_res[] = {
        [FR_TIME_RES_SEC]       = NSEC,
        [FR_TIME_RES_MIN]       = (int64_t)NSEC * 60,
        [FR_TIME_RES_HOUR]      = (int64_t)NSEC * 3600,
-       [FR_TIME_RES_DAY]       = (int64_t)NSEC * 386400
+       [FR_TIME_RES_DAY]       = (int64_t)NSEC * 86400
 };
 
 fr_table_num_ordered_t const fr_time_precision_table[] = {
@@ -240,249 +240,259 @@ int fr_time_delta_from_time_zone(char const *tz, fr_time_delta_t *delta)
 
 /** Create fr_time_delta_t from a string
  *
- * @param[out] out     Where to write fr_time_delta_t
- * @param[in] in       String to parse.
- * @param[in] hint     scale for the parsing.  Default is "seconds"
+ * @param[out] out             Where to write fr_time_delta_t
+ * @param[in] in               String to parse.
+ * @param[in] hint             scale for the parsing.  Default is "seconds".
+ * @param[in] no_trailing      asserts that there should be a terminal sequence
+ *                             after the time delta.  Allows us to produce
+ *                             better errors.
+ * @param[in] tt               terminal sequences.
  * @return
- *     - 0 on success.
- *     - -1 on failure.
+ *     - >= 0 on success.
+ *     - <0 on failure.
  */
-int fr_time_delta_from_str(fr_time_delta_t *out, char const *in, fr_time_res_t hint)
+fr_slen_t fr_time_delta_from_substr(fr_time_delta_t *out, fr_sbuff_t *in, fr_time_res_t hint,
+                                   bool no_trailing, fr_sbuff_term_t const *tt)
 {
-       int64_t sec;
-       uint64_t subsec = 0;
-       int     scale = 1;
-       char    *p, *next = NULL;
-       bool    negative = false;
-
-       if (*in == '-') negative = true; /* catch the case of negative zero! */
-
-       sec = strtoll(in, &next, 10);
-       if (in == next) {
-       failed:
-               fr_strerror_printf("Failed parsing \"%s\" as time_delta", in);
-               return -1;
+       fr_sbuff_t              our_in = FR_SBUFF(in);
+       int64_t                 integer;        /* Whole units */
+       fr_time_res_t           res;
+       bool                    negative;
+       fr_sbuff_parse_error_t  sberr;
+       bool                    overflow;
+       fr_time_delta_t         delta;          /* The delta we're building */
+       size_t                  match_len;
+
+       negative = fr_sbuff_is_char(&our_in, '-');
+
+       if (fr_sbuff_out(&sberr, &integer, &our_in) < 0) {
+       num_error:
+               fr_strerror_printf("Failed parsing time_delta: %s",
+                                  fr_table_str_by_value(sbuff_parse_error_table, sberr, "<INVALID>"));
+               return fr_sbuff_error(&our_in);
        }
+       fr_sbuff_out_by_longest_prefix(&match_len, &res, fr_time_precision_table, &our_in, FR_TIME_RES_INVALID);
 
        /*
-        *      The input is just a number.  Scale and clamp it as appropriate.
+        *      We now determine which one of the three formats
+        *      we accept the string is in.
+        *
+        *      Either:
+        *      - <integer>[<scale>]
+        *      - <integer>.<fraction>[<scale>]
+        *      - [hours:]minutes:seconds
         */
-       if (!next || !*next) {
-               *out = fr_time_delta_from_nsec(fr_time_scale(sec, hint));
-               return 0;
-       }
 
        /*
-        *      Allow "1ns", etc.
-        */
-       if ((*next >= 'a') && (*next <= 'z')) {
-               p = next;
-               goto parse_precision;
-       }
-
-       /*
-        *      Decimal number
+        *      We have a fractional component
+        *
+        *      <integer>.<fraction>[<scale>]
         */
-       if (*next == '.') {
-               int len;
-
-               len = subsec = 0;
-
-               next++;
-               p = next;
+       if (fr_sbuff_next_if_char(&our_in, '.')) {
+               fr_sbuff_marker_t       m_f;
+               size_t                  f_len;
+               uint64_t                f;      /* Fractional units */
 
                /*
-                *      Parse the decimal portion of a number like "0.1".
+                *      Normalise as a positive integer
                 */
-               while ((*p >= '0') && (*p <= '9')) {
-                       if (len > 9) {
-                               fr_strerror_const("Too much precision for time_delta");
-                               return -1;
-                       }
-
-                       subsec *= 10;
-                       subsec += *p - '0';
-                       p++;
-                       len++;
-               }
+               if (negative) integer = -(integer);
 
                /*
-                *      We've just parsed the fractional part of "0.1"
-                *      as "1".  We need to shift it left to convert
-                *      it to nanoseconds.
+                *      Mark the start of the fractional component
                 */
-               while (len < 9) {
-                       subsec *= 10;
-                       len++;
-               }
+               fr_sbuff_marker(&m_f, &our_in);
 
-       parse_precision:
                /*
-                *      No precision qualifiers, it defaults to
-                *      whatever scale the caller passed as a hint.
+                *      Leading zeros appear to mess up integer parsing
                 */
-               if (!*p) goto do_scale;
+               fr_sbuff_adv_past_zeros(&our_in, SIZE_MAX, tt);
 
-               if ((p[0] == 's') && !p[1]) {
-                       scale = NSEC;
-                       goto done;
+               if (fr_sbuff_out(&sberr, &f, &our_in) < 0) {
+                       /*
+                        *      Crappy workaround for <num>.0
+                        *
+                        *      Advancing past the leading zeros screws
+                        *      up the fractional parsing when the
+                        *      fraction is all zeros...
+                        */
+                       if ((sberr != FR_SBUFF_PARSE_ERROR_NOT_FOUND) || (*fr_sbuff_current(&m_f) != '0')) goto num_error;
+               }
+
+               f_len = fr_sbuff_behind(&m_f);
+               if (f_len > 9) {
+                       fr_strerror_const("Too much precision for time_delta");
+                       fr_sbuff_set(&our_in, fr_sbuff_current(&m_f) + 10);
+                       return fr_sbuff_error(&our_in);
                }
 
                /*
-                *      Everything else has "ms" or "us" or "ns".
+                *      Convert to nanoseconds
                 *
-                *      "1.1ns" means "parse it as 1.1s, and then
-                *      shift it right 9 orders of magnitude to
-                *      convert it to nanoseconds.
+                *      This can't overflow.
                 */
-               if ((p[1] == 's') && (p[2] == '\0')) {
-                       if (p[0] == 'm') {
-                               scale = 1000000; /* 1,000,000 nanoseconds in a millisecond */
-                               goto done;
-                       }
+               while (f_len < 9) {
+                       f *= 10;
+                       f_len++;
+               }
 
-                       if (p[0] == 'u') {
-                               scale = 1000; /* 1,000 msec on a used */
-                               goto done;
+               /*
+                *      Look for a scale suffix
+                */
+               fr_sbuff_out_by_longest_prefix(&match_len, &res, fr_time_precision_table, &our_in, FR_TIME_RES_INVALID);
+
+               if (no_trailing && !fr_sbuff_is_terminal(&our_in, tt)) {
+               trailing_data:
+                       /* Got a qualifier but there's stuff after */
+                       if (res != FR_TIME_RES_INVALID) {
+                               fr_strerror_const("Trailing data after time_delta");
+                               return fr_sbuff_error(&our_in);
                        }
 
-                       if (p[0] == 'n') {
-                               scale = 1;
-                               goto done;
-                       }
+                       fr_strerror_const("Invalid precision qualifier for time_delta");
+                       return fr_sbuff_error(&our_in);
                }
 
+               /* Scale defaults to hint */
+               if (res == FR_TIME_RES_INVALID) res = hint;
+
                /*
-                *      minutes, hours, or days.
-                *
-                *      Fractional numbers are not allowed.
+                *      Subseconds was parsed as if it was nanoseconds.
+                *      But instead it may be something else, so it should
+                *      be truncated.
                 *
-                *      minutes / hours / days larger than 64K are disallowed.
+                *      Note that this operation can't overflow.
                 */
-               if (sec > 65535) {
-                       fr_strerror_printf("Invalid value at \"%s\"", in);
-                       return -1;
+               f *= fr_time_multiplier_by_res[res];
+               f /= NSEC;
+
+               delta = fr_time_delta_from_integer(&overflow, integer, res);
+               if (overflow) {
+               overflow:
+                       fr_strerror_printf("time_delta would %s", negative ? "underflow" : "overflow");
+                       fr_sbuff_set_to_start(&our_in);
+                       return fr_sbuff_error(&our_in);
                }
 
-               if ((p[0] == 'm') && !p[1]) {
-                       *out = fr_time_delta_from_sec(sec * 60);
-                       return 0;
-               }
+               {
+                       int64_t tmp;
 
-               if ((p[0] == 'h') && !p[1]) {
-                       *out = fr_time_delta_from_sec(sec * 3600);
-                       return 0;
-               }
+                       /*
+                        *      Add fractional and integral parts checking for overflow
+                        */
+                       if (!fr_add(&tmp, fr_time_delta_unwrap(delta), f)) goto overflow;
 
-               if ((p[0] == 'd') && !p[1]) {
-                       *out = fr_time_delta_from_sec(sec * 86400);
-                       return 0;
+                       /*
+                        *      Flip the sign back to negative
+                        */
+                       if (negative) tmp = -(tmp);
+
+                       *out = fr_time_delta_wrap(tmp);
                }
 
-       error:
-               fr_strerror_printf("Invalid time qualifier at \"%s\"", p);
-               return -1;
+               return fr_sbuff_set(in, &our_in);
+       /*
+        *      It's timestamp format
+        *
+        *      [hours:]minutes:seconds
+        */
+       } else if (fr_sbuff_next_if_char(&our_in, ':')) {
+               uint64_t                hours, minutes, seconds;
+               fr_sbuff_marker_t       m1;
+
+               res = FR_TIME_RES_SEC;
+
+               fr_sbuff_marker(&m1, &our_in);
 
-       } else if (*next == ':') {
+               if (fr_sbuff_out(&sberr, &seconds, &our_in) < 0) goto num_error;
+
+               /*
+                *      minutes:seconds
+                */
+               if (!fr_sbuff_next_if_char(&our_in, ':')) {
+                       hours = 0;
+                       minutes = negative ? -(integer) : integer;
+
+                       if (minutes > UINT16_MAX) {
+                               fr_strerror_printf("minutes component of time_delta is too large");
+                               fr_sbuff_set_to_start(&our_in);
+                               return fr_sbuff_error(&our_in);
+                       }
                /*
-                *      00:01 is at least minutes, potentially hours
+                *      hours:minutes:seconds
                 */
-               int minutes = sec;
+               } else {
+                       hours = negative ? -(integer) : integer;
+                       minutes = seconds;
 
-               p = next + 1;
-               errno = 0; /* Must be reset */
-               sec = strtoul(p, &next, 10);
-               if (p == next) goto failed;
+                       if (fr_sbuff_out(&sberr, &seconds, &our_in) < 0) goto num_error;
 
-               if (*next) goto failed;
+                       if (hours > UINT16_MAX) {
+                               fr_strerror_printf("hours component of time_delta is too large");
+                               fr_sbuff_set_to_start(&our_in);
+                               return fr_sbuff_error(&our_in);
+                       }
 
-               if (((errno = ERANGE) && ((unsigned long)sec == ULONG_MAX)) || (sec > 60)) {    /* ERANGE is for wrap detection */
-                       fr_strerror_printf("Too many seconds in \"%s\"", in);
-                       return -1;
+                       if (minutes > UINT16_MAX) {
+                               fr_strerror_printf("minutes component of time_delta is too large");
+                               return fr_sbuff_error(&m1);
+                       }
                }
 
-               if (minutes > 60) {
-                       fr_strerror_printf("Too many minutes in \"%s\"", in);
-                       return -1;
-               }
+               if (no_trailing && !fr_sbuff_is_terminal(&our_in, tt)) goto trailing_data;
 
                /*
-                *      @todo - support hours, maybe.  Even though
-                *      pretty much nothing needs them right now.
+                *      Add all the components together...
                 */
-               if (*next) goto failed;
-
-               if (negative) {
-                       *out = fr_time_delta_from_sec(((int64_t)minutes * 60) - sec);
-               } else {
-                       *out = fr_time_delta_from_sec(((int64_t)minutes * 60) + sec);
-               }
-               return 0;
-
-       } else if (*next) {
-               p = next;
-               goto error;
+               if (!fr_add(&integer, ((hours * 60) * 60) + (minutes * 60), seconds)) goto overflow;
 
-       } else {
-       do_scale:
-               switch (hint) {
-               case FR_TIME_RES_SEC:
-                       scale = NSEC;
-                       break;
-
-               case FR_TIME_RES_MSEC:
-                       scale = 1000000;
-                       break;
-
-               case FR_TIME_RES_USEC:
-                       scale = 1000;
-                       break;
-
-               case FR_TIME_RES_NSEC:
-                       scale = 1;
-                       break;
-
-               default:
-                       fr_strerror_printf("Invalid hint %d for time delta", hint);
-                       return -1;
-               }
-       }
+               /*
+                *      Flip the sign back to negative
+                */
+               if (negative) integer = -(integer);
 
-done:
+               *out = fr_time_delta_from_sec(integer);
+               return fr_sbuff_set(in, &our_in);
        /*
-        *      Subseconds was parsed as if it was nanoseconds.  But
-        *      instead it may be something else, so it should be
-        *      truncated.
+        *      Nothing fancy here it's just a time delta as an integer
         *
-        *      Note that this operation can't overflow.
+        *      <integer>[<scale>]
         */
-       subsec *= scale;
-       subsec /= NSEC;
+       } else {
+               if (no_trailing && !fr_sbuff_is_terminal(&our_in, tt)) goto trailing_data;
 
-       /*
-        *      Now sec && subsec are in the same scale.
-        */
-       if (negative) {
-               if (sec <= (INT64_MIN / scale)) {
-                       fr_strerror_const("Integer underflow in time_delta value.");
-                       return -1;
-               }
+               /* Scale defaults to hint */
+               if (res == FR_TIME_RES_INVALID) res = hint;
 
-               sec *= scale;
-               sec -= subsec;
-       } else {
-               if (sec >= (INT64_MAX / scale)) {
-                       fr_strerror_const("Integer overflow in time_delta value.");
-                       return -1;
-               }
+               /* Do the scale conversion */
+               *out = fr_time_delta_from_integer(&overflow, integer, res);
+               if (overflow) goto overflow;
 
-               sec *= scale;
-               sec += subsec;
+               return fr_sbuff_set(in, &our_in);
        }
+}
 
-       *out = fr_time_delta_wrap(sec);
+/** Create fr_time_delta_t from a string
+ *
+ * @param[out] out     Where to write fr_time_delta_t
+ * @param[in] in       String to parse.
+ * @param[in] inlen    Length of string.
+ * @param[in] hint     scale for the parsing.  Default is "seconds"
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
+{
+       fr_slen_t slen;
 
-       return 0;
+       slen = fr_time_delta_from_substr(out, &FR_SBUFF_IN(in, inlen), hint, true, NULL);
+       if (slen < 0) return slen;
+       if (slen != (fr_slen_t)inlen) {
+               fr_strerror_const("trailing data after time_delta");    /* Shouldn't happen with no_trailing */
+               return -(inlen + 1);
+       }
+       return slen;
 }
 
 DIAG_OFF(format-nonliteral)
index f187ca84bd6274a7a6c38a2a5d1e269cd55a76ca..548962eeec654cfebebe0faf253a3d1892f8e230 100644 (file)
@@ -965,7 +965,10 @@ int                fr_time_sync(void);
 int64_t                fr_time_scale(int64_t t, fr_time_res_t hint);
 
 int            fr_time_delta_from_time_zone(char const *tz, fr_time_delta_t *delta) CC_HINT(nonnull);
-int            fr_time_delta_from_str(fr_time_delta_t *out, char const *in, fr_time_res_t hint) CC_HINT(nonnull);
+
+fr_slen_t      fr_time_delta_from_substr(fr_time_delta_t *out, fr_sbuff_t *in, fr_time_res_t hint,
+                                         bool no_trailing, fr_sbuff_term_t const *tt) CC_HINT(nonnull(1,2));
+fr_slen_t      fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint) CC_HINT(nonnull);
 
 size_t         fr_time_strftime_local(fr_sbuff_t *out, fr_time_t time, char const *fmt) CC_HINT(format(strftime, 3, 0));
 size_t         fr_time_strftime_utc(fr_sbuff_t *out, fr_time_t time, char const *fmt)  CC_HINT(format(strftime, 3, 0));
index 9fda0b37d8f67c3e2e69efe5f7db8d3b14215fc7..e7b2f8bd987f05c56f45149268ea0bf4f83b643c 100644 (file)
@@ -4342,6 +4342,7 @@ ssize_t fr_value_box_from_substr(TALLOC_CTX *ctx, fr_value_box_t *dst,
        fr_sbuff_t                      our_in = FR_SBUFF(in);
        ssize_t                         ret;
        char                            buffer[256];
+       fr_slen_t                       slen;
 
        if (!fr_cond_assert(dst_type != FR_TYPE_NULL)) return -1;
 
@@ -4573,9 +4574,6 @@ parse:
                return fr_value_box_from_numeric_substr(dst, dst_type, dst_enumv, in, tainted);
 
        case FR_TYPE_BOOL:
-       {
-               fr_slen_t slen;
-
                fr_value_box_init(dst, dst_type, dst_enumv, tainted);
 
                /*
@@ -4609,7 +4607,6 @@ parse:
                                 "\"yes\", \"no\", \"true\", \"false\" or any unquoted integer");
 
                return slen;    /* Just whatever the last error offset was */
-       }
 
        case FR_TYPE_ETHERNET:
        {
@@ -4680,6 +4677,15 @@ parse:
                return fr_sbuff_set(in, &our_in);
        }
 
+       case FR_TYPE_TIME_DELTA:
+               fr_value_box_init(dst, FR_TYPE_TIME_DELTA, dst_enumv, tainted);
+
+               slen = fr_time_delta_from_substr(&dst->datum.time_delta, &our_in,
+                                                dst_enumv ? dst_enumv->flags.flag_time_res : FR_TIME_RES_SEC,
+                                                false, rules->terminals);
+               if (slen < 0) return slen;
+               return fr_sbuff_set(in, &our_in);
+
        case FR_TYPE_NULL:
                if (!rules->escapes && fr_sbuff_adv_past_str_literal(in, "NULL")) {
                        fr_value_box_init(dst, dst_type, dst_enumv, tainted);
@@ -4715,14 +4721,6 @@ parse:
                if (fr_size_from_str(&dst->datum.size, buffer) < 0) return -1;
                break;
 
-       case FR_TYPE_TIME_DELTA:
-               if (dst_enumv) {
-                       if (fr_time_delta_from_str(&dst->datum.time_delta, buffer, dst_enumv->flags.flag_time_res) < 0) return -1;
-               } else {
-                       if (fr_time_delta_from_str(&dst->datum.time_delta, buffer, FR_TIME_RES_SEC) < 0) return -1;
-               }
-               break;
-
        case FR_TYPE_DATE:
        {
                if (dst_enumv) {
index e7663db383bc64cd2be7435ebc84c7a81e1a601a..70dfe2d255bc02c740265e1a24570624d1360639 100644 (file)
@@ -100,7 +100,7 @@ int main(int argc, char **argv)
                       break;
 
                case 't':
-                       if (fr_time_delta_from_str(&conf->timeout, optarg, FR_TIME_RES_SEC) < 0) {
+                       if (fr_time_delta_from_str(&conf->timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) {
                                PERROR("Failed parsing timeout value");
                                fr_exit_now(EXIT_FAILURE);
                        }
index b9b54089412c13ce235ce91245644cc85517be24..7de28cbd30bdab6fb9c0d7fabcbe6071ee553dc3 100644 (file)
@@ -38,9 +38,18 @@ match 0.000000001
 value time_delta 1:30
 match 90
 
+value time_delta 1:1:30
+match 3690
+
+value time_delta 01:01:30
+match 3690
+
 value time_delta 1h
 match 3600
 
+value time_delta 1d
+match 86400
+
 #
 #  And negative numbers
 #
@@ -68,10 +77,17 @@ match -0.000000001
 value time_delta -1:30
 match -90
 
+value time_delta -1:1:30
+match -3690
+
+value time_delta -01:01:30
+match -3690
+
 value time_delta -1h
 match -3600
 
-
+value time_delta -1d
+match -86400
 
 #
 #  uint8
@@ -215,4 +231,4 @@ encode-dns-label www_foo.com
 match Invalid character 0x5f in label
 
 count
-match 104
+match 116