summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: ffaf79c)
raw | patch | inline | side by side (parent: ffaf79c)
author | Sebastian Harl <sh@tokkee.org> | |
Fri, 4 Jul 2014 20:48:44 +0000 (22:48 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Fri, 4 Jul 2014 20:48:44 +0000 (22:48 +0200) |
The function parses a string into a datum. For date-time values, floating
point seconds since the epoch are supported only.
Added unit tests.
point seconds since the epoch are supported only.
Added unit tests.
src/core/data.c | patch | blob | history | |
src/include/core/data.h | patch | blob | history | |
src/utils/unixsock.c | patch | blob | history | |
t/unit/core/data_test.c | patch | blob | history |
diff --git a/src/core/data.c b/src/core/data.c
index ae8e662d98d22835c4dacaf23f251a5b9c1d0d29..47c54cc41e5b3e8ed881747c50f28b9a41125410 100644 (file)
--- a/src/core/data.c
+++ b/src/core/data.c
#endif /* HAVE_CONFIG_H */
#include "core/data.h"
+#include "utils/error.h"
+
+#include <errno.h>
#include <inttypes.h>
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 : */
index da653ce3f47e1f9692584b016da5e3d176ac4f80..4d7fda31c11d590a865fc6aff0665292249f0014 100644 (file)
--- a/src/include/core/data.h
+++ b/src/include/core/data.h
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 1a4373abb4ee92bc38b0cb23982f36d93b61f490..6f4d5cc2e090350be92920ed3d074a18adaf091a 100644 (file)
--- a/src/utils/unixsock.c
+++ b/src/utils/unixsock.c
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,
++next;
}
- if (sdb_unixsock_parse_cell(line,
+ if (sdb_data_parse(line,
types ? types[i] : SDB_TYPE_STRING, &data[i]))
return -1;
index e0ff3a88cb9c5d684bcb66345dd3df7977b12e71..0ce93bced809b379c91513c6bc697c9ddc98ece3 100644 (file)
--- a/t/unit/core/data_test.c
+++ b/t/unit/core/data_test.c
}
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>) = %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, <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, <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, <d>) modified input string",
+ golden_data[i].input, type);
+ }
+}
+END_TEST
+
Suite *
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;