return SR_OK;
}
+/**
+ * Convert a string representation of a numeric value to a @sr_rational. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid number. The function sets errno according to the details of the
+ * failure. This version ignores the locale.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to sr_rational where the result of the conversion will be stored.
+ *
+ * @retval SR_OK Conversion successful.
+ * @retval SR_ERR Failure.
+ *
+ * @since 0.5.0
+ */
+SR_API int sr_parse_rational(const char *str, struct sr_rational *ret)
+{
+ char *endptr = NULL;
+ int64_t integral;
+ int64_t fractional = 0;
+ int64_t denominator = 1;
+ int32_t fractional_len = 0;
+ int32_t exponent = 0;
+
+ errno = 0;
+ integral = g_ascii_strtoll(str, &endptr, 10);
+
+ if (errno)
+ return SR_ERR;
+
+ if (*endptr == '.') {
+ const char* start = endptr + 1;
+ fractional = g_ascii_strtoll(start, &endptr, 10);
+ if (errno)
+ return SR_ERR;
+ fractional_len = endptr - start;
+ }
+
+ if ((*endptr == 'E') || (*endptr == 'e')) {
+ exponent = g_ascii_strtoll(endptr + 1, &endptr, 10);
+ if (errno)
+ return SR_ERR;
+ }
+
+ if (*endptr != '\0')
+ return SR_ERR;
+
+ for (int i = 0; i < fractional_len; i++)
+ integral *= 10;
+ exponent -= fractional_len;
+
+ if (integral >= 0)
+ integral += fractional;
+ else
+ integral -= fractional;
+
+ while (exponent > 0) {
+ integral *= 10;
+ exponent--;
+ }
+
+ while (exponent < 0) {
+ denominator *= 10;
+ exponent++;
+ }
+
+ ret->p = integral;
+ ret->q = denominator;
+
+ return SR_OK;
+}
+
/**
* Convert a numeric value value to its "natural" string representation
* in SI units.
g_free(s);
}
+static void test_rational(const char *input, struct sr_rational expected)
+{
+ int ret;
+ struct sr_rational rational;
+
+ ret = sr_parse_rational(input, &rational);
+ fail_unless(ret == SR_OK);
+ fail_unless((expected.p == rational.p) && (expected.q == rational.q),
+ "Invalid result for '%s': %ld/%ld'.",
+ input, rational.p, rational.q);
+}
+
/*
* Check various inputs for sr_samplerate_string():
*
}
END_TEST
+START_TEST(test_integral)
+{
+ test_rational("1", (struct sr_rational){1, 1});
+ test_rational("2", (struct sr_rational){2, 1});
+ test_rational("10", (struct sr_rational){10, 1});
+ test_rational("-255", (struct sr_rational){-255, 1});
+}
+END_TEST
+
+START_TEST(test_fractional)
+{
+ test_rational("0.1", (struct sr_rational){1, 10});
+ test_rational("1.0", (struct sr_rational){10, 10});
+ test_rational("1.2", (struct sr_rational){12, 10});
+ test_rational("12.34", (struct sr_rational){1234, 100});
+ test_rational("-12.34", (struct sr_rational){-1234, 100});
+ test_rational("10.00", (struct sr_rational){1000, 100});
+}
+END_TEST
+
+START_TEST(test_exponent)
+{
+ test_rational("1e0", (struct sr_rational){1, 1});
+ test_rational("1E0", (struct sr_rational){1, 1});
+ test_rational("1E1", (struct sr_rational){10, 1});
+ test_rational("1e-1", (struct sr_rational){1, 10});
+ test_rational("-1.234e-0", (struct sr_rational){-1234, 1000});
+ test_rational("-1.234e3", (struct sr_rational){-1234, 1});
+ test_rational("-1.234e-3", (struct sr_rational){-1234, 1000000});
+ test_rational("0.001e3", (struct sr_rational){1, 1});
+ test_rational("0.001e0", (struct sr_rational){1, 1000});
+ test_rational("0.001e-3", (struct sr_rational){1, 1000000});
+}
+END_TEST
+
Suite *suite_strutil(void)
{
Suite *s;
tcase_add_test(tc, test_khz);
tcase_add_test(tc, test_mhz);
tcase_add_test(tc, test_ghz);
+ tcase_add_test(tc, test_integral);
+ tcase_add_test(tc, test_fractional);
+ tcase_add_test(tc, test_exponent);
suite_add_tcase(s, tc);
return s;