From: Sebastian Harl Date: Fri, 4 Jul 2014 20:48:44 +0000 (+0200) Subject: unixsock, data: Moved sdb_unixsock_parse_cell() to sdb_data_parse(). X-Git-Tag: sysdb-0.3.0~82 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=6ceaca1424cee5339613b2622ee8e160168fda1b unixsock, data: Moved sdb_unixsock_parse_cell() to sdb_data_parse(). The function parses a string into a datum. For date-time values, floating point seconds since the epoch are supported only. Added unit tests. --- diff --git a/src/core/data.c b/src/core/data.c index ae8e662..47c54cc 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -30,6 +30,9 @@ #endif /* HAVE_CONFIG_H */ #include "core/data.h" +#include "utils/error.h" + +#include #include @@ -255,5 +258,61 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) return ret; } /* sdb_data_format */ +int +sdb_data_parse(char *str, int type, sdb_data_t *data) +{ + sdb_data_t tmp; + + char *endptr = NULL; + + errno = 0; + switch (type) { + case SDB_TYPE_INTEGER: + tmp.data.integer = strtoll(str, &endptr, 0); + break; + case SDB_TYPE_DECIMAL: + tmp.data.decimal = strtod(str, &endptr); + break; + case SDB_TYPE_STRING: + tmp.data.string = str; + break; + case SDB_TYPE_DATETIME: + { + double datetime = strtod(str, &endptr); + tmp.data.datetime = DOUBLE_TO_SDB_TIME(datetime); + } + break; + case SDB_TYPE_BINARY: + /* we don't support any binary information containing 0-bytes */ + tmp.data.binary.length = strlen(str); + tmp.data.binary.datum = (unsigned char *)str; + break; + default: + errno = EINVAL; + return -1; + } + + if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL) + || (type == SDB_TYPE_DATETIME)) { + if (errno || (str == endptr)) { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "core: Failed to parse string " + "'%s' as numeric value (type %i): %s", str, type, + sdb_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + else if (endptr && (*endptr != '\0')) + sdb_log(SDB_LOG_WARNING, "core: Ignoring garbage after " + "number while parsing numeric value (type %i): %s.", + type, endptr); + } + + if (data) { + *data = tmp; + data->type = type; + } + return 0; +} /* sdb_data_parse */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/src/include/core/data.h b/src/include/core/data.h index da653ce..4d7fda3 100644 --- a/src/include/core/data.h +++ b/src/include/core/data.h @@ -146,6 +146,26 @@ enum { int sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted); +/* + * sdb_data_parse: + * Parse the specified string into a datum using the specified type. The + * string value is expected to be a raw value of the specified type. Integer + * and decimal numbers may be signed or unsigned octal (base 8, if the first + * character of the string is "0"), sedecimal (base 16, if the string includes + * the "0x" prefix), or decimal. Decimal numbers may also be "infinity" or + * "NaN" or may use a decimal exponent. Date-time values are expected to be + * specified as (floating point) number of seconds since the epoch. For string + * and binary data, the input string is passed to the datum. The function does + * not allocate new memory for that purpose. Use sdb_data_copy() if you want + * to do that. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_data_parse(char *str, int type, sdb_data_t *data); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/utils/unixsock.c b/src/utils/unixsock.c index 1a4373a..6f4d5cc 100644 --- a/src/utils/unixsock.c +++ b/src/utils/unixsock.c @@ -91,59 +91,6 @@ sdb_unixsock_get_column_count(const char *string, const char *delim) return count; } /* sdb_unixsock_get_column_count */ -static int -sdb_unixsock_parse_cell(char *string, int type, sdb_data_t *data) -{ - char *endptr = NULL; - - switch (type) { - case SDB_TYPE_INTEGER: - errno = 0; - data->data.integer = strtoll(string, &endptr, 0); - break; - case SDB_TYPE_DECIMAL: - errno = 0; - data->data.decimal = strtod(string, &endptr); - break; - case SDB_TYPE_STRING: - data->data.string = string; - break; - case SDB_TYPE_DATETIME: - { - double datetime = strtod(string, &endptr); - data->data.datetime = DOUBLE_TO_SDB_TIME(datetime); - } - break; - case SDB_TYPE_BINARY: - /* we don't support any binary information containing 0-bytes */ - data->data.binary.length = strlen(string); - data->data.binary.datum = (unsigned char *)string; - break; - default: - sdb_log(SDB_LOG_ERR, "unixsock: Unexpected type %i while " - "parsing query result.", type); - return -1; - } - - if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL) - || (type == SDB_TYPE_DATETIME)) { - if (errno || (string == endptr)) { - char errbuf[1024]; - sdb_log(SDB_LOG_ERR, "unixsock: Failed to parse string " - "'%s' as numeric value (type %i): %s", string, type, - sdb_strerror(errno, errbuf, sizeof(errbuf))); - return -1; - } - else if (endptr && (*endptr != '\0')) - sdb_log(SDB_LOG_WARNING, "unixsock: Ignoring garbage after " - "number while parsing numeric value (type %i): %s.", - type, endptr); - } - - data->type = type; - return 0; -} /* sdb_unixsock_parse_cell */ - static int sdb_unixsock_client_process_one_line(sdb_unixsock_client_t *client, char *line, sdb_unixsock_client_data_cb callback, @@ -178,7 +125,7 @@ sdb_unixsock_client_process_one_line(sdb_unixsock_client_t *client, ++next; } - if (sdb_unixsock_parse_cell(line, + if (sdb_data_parse(line, types ? types[i] : SDB_TYPE_STRING, &data[i])) return -1; diff --git a/t/unit/core/data_test.c b/t/unit/core/data_test.c index e0ff3a8..0ce93bc 100644 --- a/t/unit/core/data_test.c +++ b/t/unit/core/data_test.c @@ -365,6 +365,59 @@ START_TEST(test_format) } END_TEST +START_TEST(test_parse) +{ + struct { + char *input; + sdb_data_t result; + int expected; + } golden_data[] = { + { "4711", { SDB_TYPE_INTEGER, { .integer = 4711 } }, 0 }, + { "0x10", { SDB_TYPE_INTEGER, { .integer = 16 } }, 0 }, + { "010", { SDB_TYPE_INTEGER, { .integer = 8 } }, 0 }, + { "abc", { SDB_TYPE_INTEGER, { .integer = 0 } }, -1 }, + { "1.2", { SDB_TYPE_DECIMAL, { .decimal = 1.2 } }, 0 }, + { "0x1p+16", { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, 0 }, + { "abc", { SDB_TYPE_DECIMAL, { .decimal = 0.0 } }, -1 }, + { "abc", { SDB_TYPE_STRING, { .string = "abc" } }, 0 }, + { ".4", { SDB_TYPE_DATETIME, { .datetime = 400000000 } }, 0 }, + { "abc", { SDB_TYPE_DATETIME, { .datetime = 0 } }, -1 }, + { "abc", { SDB_TYPE_BINARY, + { .binary = { 3, (unsigned char *)"abc" } } }, 0 }, + }; + + size_t i; + + for (i = 0; i < SDB_STATIC_ARRAY_LEN(golden_data); ++i) { + sdb_data_t result; + int type, check; + + memset(&result, 0, sizeof(result)); + type = golden_data[i].result.type; + check = sdb_data_parse(golden_data[i].input, type, &result); + fail_unless(check == golden_data[i].expected, + "sdb_data_parse(%s, %d, ) = %d; expected: %d", + golden_data[i].input, type, check, golden_data[i].expected); + + if (check) + continue; + + fail_unless(sdb_data_cmp(&result, &golden_data[i].result) == 0, + "sdb_data_parse(%s, %d, ) did not create expected result", + golden_data[i].input, type); + + if (type == SDB_TYPE_STRING) + fail_unless(golden_data[i].input == result.data.string, + "sdb_data_parse(%s, %d, ) modified input string", + golden_data[i].input, type); + if (type == SDB_TYPE_BINARY) + fail_unless(golden_data[i].input == (char *)result.data.binary.datum, + "sdb_data_parse(%s, %d, ) modified input string", + golden_data[i].input, type); + } +} +END_TEST + Suite * core_data_suite(void) { @@ -375,6 +428,7 @@ core_data_suite(void) tcase_add_test(tc, test_data); tcase_add_test(tc, test_cmp); tcase_add_test(tc, test_format); + tcase_add_test(tc, test_parse); suite_add_tcase(s, tc); return s;