RETURN_OK(slen);
}
+/** Perform casting
+ *
+ */
+static size_t command_cast(command_result_t *result, command_file_ctx_t *cc,
+ char *data, UNUSED size_t data_used, char *in, size_t inlen)
+{
+ fr_value_box_t *a, *out;
+ size_t match_len;
+ fr_type_t type;
+ char const *p, *value, *end;
+ size_t slen;
+
+ a = talloc_zero(cc->tmp_ctx, fr_value_box_t);
+
+ p = in;
+ end = in + inlen;
+
+ match_len = parse_typed_value(result, a, &value, p, end - p);
+ if (match_len == 0) return 0; /* errors have already been updated */
+
+ p += match_len;
+ fr_skip_whitespace(p);
+
+ out = talloc_zero(cc->tmp_ctx, fr_value_box_t);
+
+ if (strncmp(p, "->", 2) != 0) RETURN_PARSE_ERROR(0);
+ p += 2;
+ fr_skip_whitespace(p);
+
+ type = fr_table_value_by_longest_prefix(&match_len, fr_type_table, p, end - p, FR_TYPE_MAX);
+ if (type == FR_TYPE_MAX) RETURN_PARSE_ERROR(0);
+ fr_value_box_init(out, type, NULL, false);
+
+ if (fr_value_box_cast(out, out, type, NULL, a) < 0) {
+ RETURN_OK_WITH_ERROR();
+ }
+
+ slen = fr_value_box_print(&FR_SBUFF_OUT(data, COMMAND_OUTPUT_MAX), out, NULL);
+ if (slen <= 0) RETURN_OK_WITH_ERROR();
+
+ RETURN_OK(slen);
+}
+
/** Change the working directory
*
*/
.usage = "calc_nary op <type1> <value1> <type2> <value2> ... -> <output-type>",
.description = "Perform calculations on value boxes",
}},
+ { L("cast "), &(command_entry_t){
+ .func = command_cast,
+ .usage = "cast (type) <value> -> <output-type>",
+ .description = "Perform calculations on value boxes",
+ }},
{ L("cd "), &(command_entry_t){
.func = command_cd,
.usage = "cd <path>",
return 0;
}
+ case FR_TYPE_FLOAT32:
+ if (src->vb_float32 < (double) fr_value_box_integer_min[dst_type]) {
+ underflow:
+ fr_strerror_const("Source value for cast would underflow destination type");
+ return -1;
+ }
+
+ if (src->vb_float32 > (double) fr_value_box_integer_max[dst_type]) {
+ overflow:
+ fr_strerror_const("Source value for cast would overflow destination type");
+ return -1;
+ }
+
+ switch (dst_type) {
+ case FR_TYPE_UINT8:
+ dst->vb_uint8 = src->vb_float32;
+ break;
+
+ case FR_TYPE_UINT16:
+ dst->vb_uint16 = src->vb_float32;
+ break;
+
+ case FR_TYPE_UINT32:
+ dst->vb_uint32 = src->vb_float32;
+ break;
+
+ case FR_TYPE_UINT64:
+ dst->vb_uint64 = src->vb_float32;
+ break;
+
+ case FR_TYPE_INT8:
+ dst->vb_int8 = src->vb_float32;
+ break;
+
+ case FR_TYPE_INT16:
+ dst->vb_int16 = src->vb_float32;
+ break;
+
+ case FR_TYPE_INT32:
+ dst->vb_int32 = src->vb_float32;
+ break;
+
+ case FR_TYPE_INT64:
+ dst->vb_int64 = src->vb_float32;
+ break;
+
+ case FR_TYPE_SIZE:
+ dst->vb_size = src->vb_float32;
+ break;
+
+ case FR_TYPE_DATE: {
+ int64_t sec, nsec;
+
+ sec = src->vb_float32;
+ sec *= NSEC;
+ nsec = ((src->vb_float32 * NSEC) - ((float) sec));
+
+ dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
+ }
+ break;
+
+ case FR_TYPE_TIME_DELTA: {
+ int64_t sec, nsec;
+
+ sec = src->vb_float32;
+ sec *= NSEC;
+ nsec = ((src->vb_float32 * NSEC) - ((float) sec));
+
+ dst->vb_time_delta = fr_time_delta_from_nsec(sec + nsec);
+ }
+ break;
+
+ default:
+ goto bad_cast;
+ }
+ return 0;
+
+ case FR_TYPE_FLOAT64:
+ if (src->vb_float64 < (double) fr_value_box_integer_min[dst_type]) goto underflow;
+
+ if (src->vb_float64 > (double) fr_value_box_integer_max[dst_type]) goto overflow;
+
+ switch (dst_type) {
+ case FR_TYPE_UINT8:
+ dst->vb_uint8 = src->vb_float64;
+ break;
+
+ case FR_TYPE_UINT16:
+ dst->vb_uint16 = src->vb_float64;
+ break;
+
+ case FR_TYPE_UINT32:
+ dst->vb_uint32 = src->vb_float64;
+ break;
+
+ case FR_TYPE_UINT64:
+ dst->vb_uint64 = src->vb_float64;
+ break;
+
+ case FR_TYPE_INT8:
+ dst->vb_int8 = src->vb_float64;
+ break;
+
+ case FR_TYPE_INT16:
+ dst->vb_int16 = src->vb_float64;
+ break;
+
+ case FR_TYPE_INT32:
+ dst->vb_int32 = src->vb_float64;
+ break;
+
+ case FR_TYPE_INT64:
+ dst->vb_int64 = src->vb_float64;
+ break;
+
+ case FR_TYPE_SIZE:
+ dst->vb_size = src->vb_float64;
+ break;
+
+ case FR_TYPE_DATE: {
+ int64_t sec, nsec;
+
+ sec = src->vb_float64;
+ sec *= NSEC;
+ nsec = ((src->vb_float64 * NSEC) - ((double) sec));
+
+ /*
+ * @todo - respect time res
+ */
+ dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
+ }
+ break;
+
+ case FR_TYPE_TIME_DELTA: {
+ int64_t sec, nsec;
+ int64_t res = NSEC;
+ bool fail = false;
+
+ if (dst->enumv) res = fr_time_multiplier_by_res[dst->enumv->flags.flag_time_res];
+
+ sec = src->vb_float64;
+ sec *= res;
+ nsec = ((src->vb_float64 * res) - ((double) sec));
+
+ dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
+ dst->enumv ? dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
+ if (fail) goto overflow;
+ }
+ break;
+
+ default:
+ goto bad_cast;
+ }
+ return 0;
+
default:
break;
}
test_fail
}
-if (%cast("weeks", 8d) != 1.864) {
+#
+# Change of scale doesn't affect the numbers. Internally, the
+# time_deltas are stored as nanoseconds since epoch. The scale only
+# matters for parsing and printing.
+#
+if 7d != 1w {
+ test_fail
+}
+
+#
+# 8/7 is about 1.142.... But since the integers are 64-bit,
+# they have a lot more precision than the floating point numbers.
+# As a result, we look for approximate equality.
+#
+if ((%cast("weeks", 8d) - 1.14285714w) >= 1s) {
test_fail
}
--- /dev/null
+cast ipaddr 127.0.0.1 -> uint32
+match 2130706433
+
+cast ipaddr 127.0.0.1 -> octets
+match 0x7f000001
+
+cast float64 0.5 -> time_delta
+match 0.5
+
+cast float64 -0.5 -> time_delta
+match -0.5
+
+cast float64 6.25 -> time_delta
+match 6.25
+
+cast float64 1024 -> uint8
+match Source value for cast would overflow destination type
+
+#
+# Input can be qualified with a resolution. Output is seconds by default.
+#
+cast time_delta 6.25s -> time_delta
+match 6.25
+
+cast time_delta 1w -> time_delta
+match 604800
+
+cast time_delta 6.25ms -> time_delta
+match 0.00625
+
+cast time_delta 6.25us -> time_delta
+match 0.00000625
+
+cast time_delta 8d -> time_delta
+match 691200
+
+#
+# This is 8/7 of a week, or 8 days
+#
+cast time_delta 1.14285714w -> time_delta
+match 691199.998272
+
+count
+match 24