diff --git a/sys/fmt/fmt.c b/sys/fmt/fmt.c index d0d96b354f..0d012ed1cc 100644 --- a/sys/fmt/fmt.c +++ b/sys/fmt/fmt.c @@ -48,21 +48,25 @@ static const uint32_t _tenmap[] = { #define TENMAP_SIZE ARRAY_SIZE(_tenmap) -static inline int _is_digit(char c) -{ - return (c >= '0' && c <= '9'); -} - -static inline int _is_upper(char c) -{ - return (c >= 'A' && c <= 'Z'); -} - static inline char _to_lower(char c) { return 'a' + (c - 'A'); } +int fmt_is_number(const char *str) +{ + if (!str || !*str) { + return 0; + } + for (; *str; str++) { + if (!fmt_is_digit(*str)) { + return 0; + } + } + + return 1; +} + size_t fmt_byte_hex(char *out, uint8_t byte) { if (out) { @@ -437,7 +441,7 @@ size_t fmt_to_lower(char *out, const char *str) size_t len = 0; while (str && *str) { - if (_is_upper(*str)) { + if (fmt_is_upper(*str)) { if (out) { *out++ = _to_lower(*str); } @@ -457,7 +461,7 @@ uint32_t scn_u32_dec(const char *str, size_t n) uint32_t res = 0; while(n--) { char c = *str++; - if (!_is_digit(c)) { + if (!fmt_is_digit(c)) { break; } else { @@ -474,8 +478,8 @@ uint32_t scn_u32_hex(const char *str, size_t n) while (n--) { char c = *str++; - if (!_is_digit(c)) { - if (_is_upper(c)) { + if (!fmt_is_digit(c)) { + if (fmt_is_upper(c)) { c = _to_lower(c); } if (c == '\0' || c > 'f') { diff --git a/sys/include/fmt.h b/sys/include/fmt.h index f38473b631..8e89906ef8 100644 --- a/sys/include/fmt.h +++ b/sys/include/fmt.h @@ -45,6 +45,39 @@ extern "C" { #define FMT_USE_MEMMOVE (1) /**< use memmove() or internal implementation */ #endif +/** + * @brief Test if the given character is a numerical digit (regex `[0-9]`) + * + * @param[in] c Character to test + * + * @return true if @p c is a digit, false otherwise + */ +static inline int fmt_is_digit(char c) +{ + return (c >= '0' && c <= '9'); +} + +/** + * @brief Test if the given character is an uppercase letter (regex `[A-Z]`) + * + * @param[in] c Character to test + * + * @return true if @p c is an uppercase letter, false otherwise + */ +static inline int fmt_is_upper(char c) +{ + return (c >= 'A' && c <= 'Z'); +} + +/** + * @brief Test if the given string is a number (regex `[0-9]+`) + * + * @param[in] str String to test, **must be `\0` terminated** + * + * @return true if @p str solely contains digits, false otherwise + */ +int fmt_is_number(const char *str); + /** * @brief Format a byte value as hex * diff --git a/sys/shell/commands/sc_gnrc_netif.c b/sys/shell/commands/sc_gnrc_netif.c index 2031e0241f..62097f5a14 100644 --- a/sys/shell/commands/sc_gnrc_netif.c +++ b/sys/shell/commands/sc_gnrc_netif.c @@ -78,17 +78,6 @@ static const struct { }; /* utility functions */ -static bool _is_number(char *str) -{ - for (; *str; str++) { - if (*str < '0' || *str > '9') { - return false; - } - } - - return true; -} - static void _print_iface_name(netif_t *iface) { char name[NETIF_NAMELENMAX]; @@ -684,7 +673,7 @@ static int _netif_set_u32(netif_t *iface, netopt_t opt, uint32_t context, unsigned long int res; bool hex = false; - if (_is_number(u32_str)) { + if (fmt_is_number(u32_str)) { if ((res = strtoul(u32_str, NULL, 10)) == ULONG_MAX) { puts("error: unable to parse value.\n" "Must be a 32-bit unsigned integer (dec or hex)\n"); @@ -796,7 +785,7 @@ static int _netif_set_u16(netif_t *iface, netopt_t opt, uint16_t context, unsigned long int res; bool hex = false; - if (_is_number(u16_str)) { + if (fmt_is_number(u16_str)) { if ((res = strtoul(u16_str, NULL, 10)) == ULONG_MAX) { puts("error: unable to parse value.\n" "Must be a 16-bit unsigned integer (dec or hex)\n"); diff --git a/tests/driver_kw2xrf/Makefile b/tests/driver_kw2xrf/Makefile index 6b4111e418..b0fa0e447e 100644 --- a/tests/driver_kw2xrf/Makefile +++ b/tests/driver_kw2xrf/Makefile @@ -2,6 +2,7 @@ include ../Makefile.tests_common USEMODULE += auto_init_gnrc_netif USEMODULE += gnrc_netdev_default +USEMODULE += fmt USEMODULE += shell USEMODULE += shell_commands USEMODULE += ps diff --git a/tests/driver_kw2xrf/main.c b/tests/driver_kw2xrf/main.c index 99ee100d1f..86a7fd8d3e 100644 --- a/tests/driver_kw2xrf/main.c +++ b/tests/driver_kw2xrf/main.c @@ -19,6 +19,7 @@ #include +#include "fmt.h" #include "shell.h" #include "kw2xrf.h" #include "shell_commands.h" @@ -32,21 +33,10 @@ #include "kw2xrf_tm.h" /* utility functions */ -static bool _is_number(char *str) -{ - for (; *str; str++) { - if (*str < '0' || *str > '9') { - return false; - } - } - - return true; -} - static void _set_test_mode(int argc, char **argv, uint8_t mode) { (void) argc; - if (_is_number(argv[1])) { + if (fmt_is_number(argv[1])) { kernel_pid_t dev = atoi(argv[1]); if (gnrc_netif_get_by_pid(dev)) { diff --git a/tests/unittests/tests-fmt/tests-fmt.c b/tests/unittests/tests-fmt/tests-fmt.c index 8126beafcc..e321dc99cc 100644 --- a/tests/unittests/tests-fmt/tests-fmt.c +++ b/tests/unittests/tests-fmt/tests-fmt.c @@ -20,6 +20,28 @@ #include "fmt.h" #include "tests-fmt.h" +static void test_fmt_is_x(void) +{ + const char *num = "123"; + const char *hex = "0xabc"; + const char *str = "muh"; + char digit = '8'; + char lower = 'a'; + char upper = 'A'; + + TEST_ASSERT_EQUAL_INT(1, fmt_is_digit(digit)); + TEST_ASSERT_EQUAL_INT(0, fmt_is_digit(lower)); + TEST_ASSERT_EQUAL_INT(0, fmt_is_digit(upper)); + + TEST_ASSERT_EQUAL_INT(0, fmt_is_upper(digit)); + TEST_ASSERT_EQUAL_INT(0, fmt_is_upper(lower)); + TEST_ASSERT_EQUAL_INT(1, fmt_is_upper(upper)); + + TEST_ASSERT_EQUAL_INT(1, fmt_is_number(num)); + TEST_ASSERT_EQUAL_INT(0, fmt_is_number(hex)); + TEST_ASSERT_EQUAL_INT(0, fmt_is_number(str)); +} + static void test_fmt_byte_hex(void) { char out[8] = "zzzzzzz"; @@ -825,6 +847,7 @@ static void test_fmt_lpad(void) Test *tests_fmt_tests(void) { EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_fmt_is_x), new_TestFixture(test_fmt_byte_hex), new_TestFixture(test_fmt_bytes_hex), new_TestFixture(test_fmt_bytes_hex_reverse),