X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fcore%2Fdata.c;h=9890aafb65c80fded00ba1db13db3390908bfef9;hb=abddd8616349bc2a18e96f1efcb16a5af57401da;hp=1188b4030ba4215304c4f7a47ae25e68a5feb49f;hpb=842fabc3dcb86bc6863c4ae6c0b7a21fbb7e8ccc;p=sysdb.git diff --git a/src/core/data.c b/src/core/data.c index 1188b40..9890aaf 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -34,6 +34,8 @@ #include "core/data.h" #include "utils/error.h" +#include + #include #include @@ -200,20 +202,17 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) else return -1; - if (s1 || s2) { - new = malloc(len1 + len2 + 1); - if (! new) - return -1; - } - else - new = NULL; + assert(s1 && s2); + + new = malloc(len1 + len2 + 1); + if (! new) + return -1; if (len1) memcpy(new, s1, len1); if (len2) memcpy(new + len1, s2, len2); - if (new) - new[len1 + len2] = '\0'; + new[len1 + len2] = '\0'; res->type = d1->type; if (res->type == SDB_TYPE_STRING) { @@ -230,6 +229,8 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) * public API */ +const sdb_data_t SDB_DATA_NULL = SDB_DATA_INIT; + int sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src) { @@ -241,16 +242,36 @@ sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src) tmp = *src; switch (src->type) { case SDB_TYPE_STRING: - tmp.data.string = strdup(src->data.string); - if (! tmp.data.string) - return -1; + if (src->data.string) { + tmp.data.string = strdup(src->data.string); + if (! tmp.data.string) + return -1; + } break; case SDB_TYPE_BINARY: - tmp.data.binary.datum = malloc(src->data.binary.length); - if (! tmp.data.binary.datum) - return -1; - memcpy(tmp.data.binary.datum, src->data.binary.datum, - src->data.binary.length); + if (src->data.binary.datum) { + tmp.data.binary.datum = malloc(src->data.binary.length); + if (! tmp.data.binary.datum) + return -1; + memcpy(tmp.data.binary.datum, src->data.binary.datum, + src->data.binary.length); + } + break; + case SDB_TYPE_REGEX: + if (src->data.re.raw) { + tmp.data.re.raw = strdup(src->data.re.raw); + if (! tmp.data.re.raw) + return -1; + /* we need to recompile because the regex might point to + * dynamically allocated memory */ + if (regcomp(&tmp.data.re.regex, tmp.data.re.raw, + REG_EXTENDED | REG_ICASE | REG_NOSUB)) { + free(tmp.data.re.raw); + return -1; + } + } + else + memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex)); break; } @@ -277,6 +298,14 @@ sdb_data_free_datum(sdb_data_t *datum) datum->data.binary.datum = NULL; datum->data.binary.length = 0; break; + case SDB_TYPE_REGEX: + if (datum->data.re.raw) { + free(datum->data.re.raw); + regfree(&datum->data.re.regex); + } + datum->data.re.raw = NULL; + memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex)); + break; } } /* sdb_data_free_datum */ @@ -328,18 +357,79 @@ sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2) return diff; } - default: - return -1; + case SDB_TYPE_REGEX: + CMP_NULL(d1->data.re.raw, d2->data.re.raw); + return strcmp(d1->data.re.raw, d2->data.re.raw); } -#undef CMP_NULL + return -1; } /* sdb_data_cmp */ +int +sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2) +{ + char d1_str[sdb_data_strlen(d1) + 1]; + char d2_str[sdb_data_strlen(d2) + 1]; + + if (sdb_data_isnull(d1)) + d1 = NULL; + if (sdb_data_isnull(d2)) + d2 = NULL; + + CMP_NULL(d1, d2); + + if (sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED) < 0) + return SDB_CMP(sizeof(d1_str), sizeof(d2_str)); + if (sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED) < 0) + return SDB_CMP(sizeof(d1_str), sizeof(d2_str)); + + return strcasecmp(d1_str, d2_str); +#undef CMP_NULL +} /* sdb_data_strcmp */ + +_Bool +sdb_data_isnull(const sdb_data_t *datum) +{ + if (! datum) + return 1; + if (datum->type == SDB_TYPE_NULL) + return 1; + if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string)) + return 1; + if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum)) + return 1; + if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw)) + return 1; + return 0; +} /* sdb_data_isnull */ + +int +sdb_data_parse_op(const char *op) +{ + if (! strcmp(op, "+")) + return SDB_DATA_ADD; + else if (! strcmp(op, "-")) + return SDB_DATA_SUB; + else if (! strcmp(op, "*")) + return SDB_DATA_MUL; + else if (! strcmp(op, "/")) + return SDB_DATA_DIV; + else if (! strcmp(op, "%")) + return SDB_DATA_MOD; + else if (! strcmp(op, "||")) + return SDB_DATA_CONCAT; + return -1; +} /* sdb_data_parse_op */ + int sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) { if ((! d1) || (! d2) || (! res)) return -1; + if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) { + *res = SDB_DATA_NULL; + return 0; + } switch (op) { case SDB_DATA_CONCAT: return data_concat(d1, d2, res); @@ -368,19 +458,26 @@ sdb_data_strlen(const sdb_data_t *datum) /* log(64) */ return 20; case SDB_TYPE_DECIMAL: - /* XXX: -0xN.NNNNNNp+NNN */ + /* XXX: -d.dddddde+dd or -ddddd.dddddd */ return 42; case SDB_TYPE_STRING: if (! datum->data.string) - return 6; /* "NULL" */ + return 8; /* "" */ /* in the worst case, each character needs to be escaped */ return 2 * strlen(datum->data.string) + 2; case SDB_TYPE_DATETIME: /* "YYYY-MM-DD HH:MM:SS +zzzz" */ return 27; case SDB_TYPE_BINARY: + if (! datum->data.binary.datum) + return 8; /* "" */ /* "\xNN" */ return 4 * datum->data.binary.length + 2; + case SDB_TYPE_REGEX: + if (! datum->data.re.raw) + return 8; /* "" */ + /* "/.../" */ + return strlen(datum->data.re.raw) + 4; } return 0; } /* sdb_data_strlen */ @@ -402,11 +499,11 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer); break; case SDB_TYPE_DECIMAL: - ret = snprintf(buf, buflen, "%a", datum->data.decimal); + ret = snprintf(buf, buflen, "%g", datum->data.decimal); break; case SDB_TYPE_STRING: if (! datum->data.string) - data = "NULL"; + data = ""; else { pos = 0; for (i = 0; i < strlen(datum->data.string); ++i) { @@ -448,8 +545,20 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) tmp[pos] = hex[byte & 0xf]; ++pos; } - tmp[pos] = '\0'; - data = tmp; + if (datum->data.binary.datum) { + tmp[pos] = '\0'; + data = tmp; + } + else + data = ""; + break; + case SDB_TYPE_REGEX: + if (! datum->data.re.raw) + data = ""; + else { + snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw); + data = tmp; + } break; } @@ -494,6 +603,22 @@ sdb_data_parse(char *str, int type, sdb_data_t *data) tmp.data.binary.length = strlen(str); tmp.data.binary.datum = (unsigned char *)str; break; + case SDB_TYPE_REGEX: + tmp.data.re.raw = strdup(str); + if (! tmp.data.re.raw) + return -1; + if (regcomp(&tmp.data.re.regex, tmp.data.re.raw, + REG_EXTENDED | REG_ICASE | REG_NOSUB)) { + sdb_log(SDB_LOG_ERR, "core: Failed to compile regular " + "expression '%s'", tmp.data.re.raw); + free(tmp.data.re.raw); + return -1; + } + if (! data) { + tmp.type = SDB_TYPE_REGEX; + sdb_data_free_datum(&tmp); + } + break; default: errno = EINVAL; return -1; @@ -521,5 +646,24 @@ sdb_data_parse(char *str, int type, sdb_data_t *data) return 0; } /* sdb_data_parse */ +size_t +sdb_data_sizeof(int type) +{ + sdb_data_t v; + if (type == SDB_TYPE_INTEGER) + return sizeof(v.data.integer); + else if (type == SDB_TYPE_DECIMAL) + return sizeof(v.data.decimal); + else if (type == SDB_TYPE_STRING) + return sizeof(v.data.string); + else if (type == SDB_TYPE_DATETIME) + return sizeof(v.data.datetime); + else if (type == SDB_TYPE_BINARY) + return sizeof(v.data.binary); + else if (type == SDB_TYPE_REGEX) + return sizeof(v.data.re); + return 0; +} /* sdb_data_sizeof */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */