X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fcore%2Fdata.c;h=22d9ba36bb80e12b0a0870446573075c09999bd3;hb=2f85566fbc79498eb7abfaf1cbd279f71f7ea8d1;hp=c1e99a8cab82ed742b76a8d8165fe44ceb999269;hpb=b60757c35490b67efbc4838f5d930a8765bcca37;p=sysdb.git diff --git a/src/core/data.c b/src/core/data.c index c1e99a8..22d9ba3 100644 --- a/src/core/data.c +++ b/src/core/data.c @@ -50,6 +50,99 @@ * private helper functions */ +/* this function supports in-place copies */ +static int +copy_array_values(sdb_data_t *dst, const sdb_data_t *src, size_t elem_size) +{ + int type = src->type & 0xff; + + if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)) { + if (dst != src) + memcpy(dst->data.array.values, src->data.array.values, + src->data.array.length * elem_size); + } + else if (type == SDB_TYPE_STRING) { + char **s = src->data.array.values; + char **d = dst->data.array.values; + size_t i; + + for (i = 0; i < src->data.array.length; ++i) { + d[i] = strdup(s[i]); + if (! d[i]) + return -1; + } + } + else { + /* TODO */ + errno = ENOTSUP; + return -1; + } + return 0; +} /* copy_array_values */ + +static void +free_array_values(sdb_data_t *datum) +{ + int type = datum->type & 0xff; + + if (type == SDB_TYPE_STRING) { + char **v = datum->data.array.values; + size_t i; + + for (i = 0; i < datum->data.array.length; ++i) { + if (v[i]) + free(v[i]); + v[i] = NULL; + } + } +} /* free_array_values */ + +/* compare two arrays element-by-element returning how the first non-equal + * elements compare to each other */ +static int +array_cmp(const sdb_data_t *a1, const sdb_data_t *a2) +{ + int type = a1->type & 0xff; + size_t len, i; + + assert((a1->type == a2->type) && (a1->type & SDB_TYPE_ARRAY)); + + len = SDB_MIN(a1->data.array.length, a2->data.array.length); + + if (type == SDB_TYPE_INTEGER) { + int64_t *v1 = a1->data.array.values; + int64_t *v2 = a2->data.array.values; + + for (i = 0; i < len; ++i) + if (v1[i] != v2[i]) + return SDB_CMP(v1[i], v2[i]); + } + else if (type == SDB_TYPE_DECIMAL) { + double *v1 = a1->data.array.values; + double *v2 = a2->data.array.values; + + for (i = 0; i < len; ++i) + if (v1[i] != v2[i]) + return SDB_CMP(v1[i], v2[i]); + } + else if (type == SDB_TYPE_STRING) { + char **v1 = a1->data.array.values; + char **v2 = a2->data.array.values; + + for (i = 0; i < len; ++i) { + int diff = strcasecmp(v1[i], v2[i]); + if (diff) + return diff; + } + } + else { + /* TODO */ + errno = ENOTSUP; + /* but fall through to ensure stable sorting: */ + } + return SDB_CMP(a1->data.array.length, a2->data.array.length); +} /* array_cmp */ + /* Calculate the linear function 'd1 + n * d2'. */ static int data_lin(const sdb_data_t *d1, int n, const sdb_data_t *d2, sdb_data_t *res) @@ -184,6 +277,7 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) unsigned char *s1, *s2; size_t len1, len2; + /* TODO: support array plus element */ if (d1->type != d2->type) return -1; @@ -199,6 +293,13 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) len1 = d1->data.binary.length; len2 = d2->data.binary.length; } + else if (d1->type & SDB_TYPE_ARRAY) { + size_t elem_size = sdb_data_sizeof(d1->type & 0xff); + s1 = (unsigned char *)d1->data.array.values; + s2 = (unsigned char *)d2->data.array.values; + len1 = d1->data.array.length * elem_size; + len2 = d2->data.array.length * elem_size; + } else return -1; @@ -218,10 +319,22 @@ data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res) if (res->type == SDB_TYPE_STRING) { res->data.string = (char *)new; } - else { + else if (res->type == SDB_TYPE_BINARY) { res->data.binary.datum = new; res->data.binary.length = len1 + len2; } + else if (d1->type & SDB_TYPE_ARRAY) { + res->data.array.values = new; + res->data.array.length = d1->data.array.length + d2->data.array.length; + if (copy_array_values(res, res, sdb_data_sizeof(res->type & 0xff))) { + /* this leaks already copied values but there's not much we can + * do and this should only happen if we're in trouble anyway */ + free(new); + res->data.array.values = NULL; + res->data.array.length = 0; + return -1; + } + } return 0; } /* data_concat */ @@ -272,6 +385,18 @@ sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src) else memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex)); } + else if (src->type & SDB_TYPE_ARRAY) { + if (src->data.array.values) { + size_t elem_size = sdb_data_sizeof(src->type & 0xff); + tmp.data.array.values = calloc(src->data.array.length, elem_size); + if (! tmp.data.array.values) + return -1; + if (copy_array_values(&tmp, src, elem_size)) { + sdb_data_free_datum(&tmp); + return -1; + } + } + } sdb_data_free_datum(dst); *dst = tmp; @@ -303,6 +428,13 @@ sdb_data_free_datum(sdb_data_t *datum) datum->data.re.raw = NULL; memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex)); } + else if (datum->type & SDB_TYPE_ARRAY) { + free_array_values(datum); + if (datum->data.array.values) + free(datum->data.array.values); + datum->data.array.values = NULL; + datum->data.array.length = 0; + } } /* sdb_data_free_datum */ int @@ -356,6 +488,10 @@ sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2) CMP_NULL(d1->data.re.raw, d2->data.re.raw); return strcmp(d1->data.re.raw, d2->data.re.raw); } + else if (d1->type & SDB_TYPE_ARRAY) { + CMP_NULL(d1->data.array.values, d2->data.array.values); + return array_cmp(d1, d2); + } return -1; } /* sdb_data_cmp */ @@ -365,6 +501,12 @@ 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 ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) { + /* TODO */ + errno = ENOTSUP; + return -1; + } + if (sdb_data_isnull(d1)) d1 = NULL; if (sdb_data_isnull(d2)) @@ -394,6 +536,8 @@ sdb_data_isnull(const sdb_data_t *datum) return 1; if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw)) return 1; + if ((datum->type & SDB_TYPE_ARRAY) && (! datum->data.array.values)) + return 1; return 0; } /* sdb_data_isnull */ @@ -478,6 +622,11 @@ sdb_data_strlen(const sdb_data_t *datum) /* "/.../" */ return strlen(datum->data.re.raw) + 4; } + else if (datum->type & SDB_TYPE_ARRAY) { + /* TODO */ + errno = ENOTSUP; + return 0; + } return 0; } /* sdb_data_strlen */ @@ -558,6 +707,11 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted) data = tmp; } } + else if (datum->type & SDB_TYPE_ARRAY) { + /* TODO */ + errno = ENOTSUP; + return -1; + } if (data) { if (quoted == SDB_UNQUOTED) @@ -613,6 +767,11 @@ sdb_data_parse(char *str, int type, sdb_data_t *data) sdb_data_free_datum(&tmp); } } + else if (type & SDB_TYPE_ARRAY) { + /* TODO */ + errno = ENOTSUP; + return -1; + } else { errno = EINVAL; return -1;