diff --git a/src/core/data.c b/src/core/data.c
index 8754f8868a11471fe1e359cee75ac0d52b87721d..9f2b1f6fe4dda241997222ec62ac4fcdabf96eb0 100644 (file)
--- a/src/core/data.c
+++ b/src/core/data.c
data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
{
unsigned char *new;
- unsigned char *s1, *s2;
- size_t len1, len2;
+ const unsigned char *s1, *s2;
+ size_t len1, len2, array1_len = 0, array2_len = 0;
- /* TODO: support array plus element */
- if (d1->type != d2->type)
+ if ((d1->type & 0xff) != (d2->type & 0xff))
return -1;
- if (d1->type == SDB_TYPE_STRING) {
+ if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
+ size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
+ if (d1->type & SDB_TYPE_ARRAY) {
+ s1 = (const unsigned char *)d1->data.array.values;
+ array1_len = d1->data.array.length;
+ }
+ else {
+ /* As per C99, section 6.7.2.1, paragraph 14:
+ * "A pointer to a union object, suitably converted, points to
+ * each of its members" */
+ s1 = (const unsigned char *)&d1->data;
+ array1_len = 1;
+ }
+ if (d2->type & SDB_TYPE_ARRAY) {
+ s2 = (const unsigned char *)d2->data.array.values;
+ array2_len = d2->data.array.length;
+ }
+ else {
+ s2 = (const unsigned char *)&d2->data;
+ array2_len = 1;
+ }
+ len1 = array1_len * elem_size;
+ len2 = array2_len * elem_size;
+ }
+ else if (d1->type == SDB_TYPE_STRING) {
s1 = (unsigned char *)d1->data.string;
s2 = (unsigned char *)d2->data.string;
- len1 = s1 ? strlen((char *)s1) : 0;
- len2 = s2 ? strlen((char *)s2) : 0;
+ len1 = s1 ? strlen((const char *)s1) : 0;
+ len2 = s2 ? strlen((const char *)s2) : 0;
}
else if (d1->type == SDB_TYPE_BINARY) {
s1 = d1->data.binary.datum;
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;
- assert(s1 && s2);
-
new = malloc(len1 + len2 + 1);
if (! new)
return -1;
memcpy(new + len1, s2, len2);
new[len1 + len2] = '\0';
- res->type = d1->type;
+ /* element types match and if either datum is an array,
+ * the result is an array as well */
+ res->type = d1->type | d2->type;
if (res->type == SDB_TYPE_STRING) {
res->data.string = (char *)new;
}
res->data.binary.datum = new;
res->data.binary.length = len1 + len2;
}
- else if (d1->type & SDB_TYPE_ARRAY) {
+ else if (res->type & SDB_TYPE_ARRAY) {
res->data.array.values = new;
- res->data.array.length = d1->data.array.length + d2->data.array.length;
+ res->data.array.length = array1_len + array2_len;
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 */
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 */
_Bool
sdb_data_inarray(const sdb_data_t *value, const sdb_data_t *array)
{
- size_t i;
+ const void *values;
+ size_t length, i;
+ int type = value->type & 0xff;
if (sdb_data_isnull(value) || sdb_data_isnull(array))
return 0;
- if ((value->type & SDB_TYPE_ARRAY) || (! (array->type & SDB_TYPE_ARRAY)))
+ if (! (array->type & SDB_TYPE_ARRAY))
return 0;
- if (value->type != (array->type & 0xff))
+ if ((value->type & 0xff) != (array->type & 0xff))
return 0;
- if (value->type == SDB_TYPE_INTEGER) {
+ if (value->type & SDB_TYPE_ARRAY) {
+ values = value->data.array.values;
+ length = value->data.array.length;
+ }
+ else {
+ values = &value->data;
+ length = 1;
+ }
+
+ for (i = 0; i < length; ++i) {
+ size_t j;
+
+ if (type == SDB_TYPE_INTEGER) {
+ int64_t *v = array->data.array.values;
+ for (j = 0; j < array->data.array.length; ++j)
+ if (((const int64_t *)values)[i] == v[j])
+ break;
+ }
+ else if (type == SDB_TYPE_DECIMAL) {
+ double *v = array->data.array.values;
+ for (j = 0; j < array->data.array.length; ++j)
+ if (((const double *)values)[i] == v[j])
+ break;
+ }
+ else if (type == SDB_TYPE_STRING) {
+ char **v = array->data.array.values;
+ for (j = 0; j < array->data.array.length; ++j)
+ if (!strcasecmp(((const char * const*)values)[i], v[j]))
+ break;
+ }
+ else {
+ /* TODO */
+ errno = ENOTSUP;
+ return 0;
+ }
+
+ if (j >= array->data.array.length)
+ /* value not found */
+ return 0;
+ }
+ return 1;
+} /* sdb_data_inarray */
+
+int
+sdb_data_array_get(const sdb_data_t *array, size_t i, sdb_data_t *value)
+{
+ sdb_data_t tmp = SDB_DATA_INIT;
+ int type;
+
+ if ((! array) || (! (array->type & SDB_TYPE_ARRAY)))
+ return -1;
+ if (i >= array->data.array.length)
+ return -1;
+
+ type = array->type & 0xff;
+ if (type == SDB_TYPE_INTEGER) {
int64_t *v = array->data.array.values;
- for (i = 0; i < array->data.array.length; ++i)
- if (value->data.integer == v[i])
- return 1;
+ tmp.data.integer = v[i];
}
- else if (value->type == SDB_TYPE_DECIMAL) {
+ else if (type == SDB_TYPE_DECIMAL) {
double *v = array->data.array.values;
- for (i = 0; i < array->data.array.length; ++i)
- if (value->data.decimal == v[i])
- return 1;
+ tmp.data.decimal = v[i];
}
- else if (value->type == SDB_TYPE_STRING) {
+ else if (type == SDB_TYPE_STRING) {
char **v = array->data.array.values;
- for (i = 0; i < array->data.array.length; ++i)
- if (!strcasecmp(value->data.string, v[i]))
- return 1;
+ tmp.data.string = v[i];
}
else {
/* TODO */
errno = ENOTSUP;
- return 0;
+ return -1;
+ }
+
+ if (value) {
+ *value = tmp;
+ value->type = type;
}
return 0;
-} /* sdb_data_inarray */
+} /* sdb_data_array_get */
int
sdb_data_parse_op(const char *op)
return 0;
}
switch (op) {
- case SDB_DATA_CONCAT:
- return data_concat(d1, d2, res);
- case SDB_DATA_ADD:
- return data_lin(d1, 1, d2, res);
- case SDB_DATA_SUB:
- return data_lin(d1, -1, d2, res);
- case SDB_DATA_MUL:
- return data_mul(d1, d2, res);
- case SDB_DATA_DIV:
- return data_div(d1, d2, res, NULL);
- case SDB_DATA_MOD:
- return data_div(d1, d2, NULL, res);
+ case SDB_DATA_CONCAT: return data_concat(d1, d2, res);
+ case SDB_DATA_ADD: return data_lin(d1, 1, d2, res);
+ case SDB_DATA_SUB: return data_lin(d1, -1, d2, res);
+ case SDB_DATA_MUL: return data_mul(d1, d2, res);
+ case SDB_DATA_DIV: return data_div(d1, d2, res, NULL);
+ case SDB_DATA_MOD: return data_div(d1, d2, NULL, res);
}
return -1;
} /* sdb_data_expr_eval */
if ((op <= 0) || (SDB_STATIC_ARRAY_LEN(op_matrix) < (size_t)op))
return -1;
- /* arrays only support concat; type has to match */
+ /* arrays only support concat; element type has to match */
if ((type1 & SDB_TYPE_ARRAY) || (type2 & SDB_TYPE_ARRAY)) {
- if ((type1 != type2) || (op != SDB_DATA_CONCAT))
+ if (((type1 & 0xff) != (type2 & 0xff)) || (op != SDB_DATA_CONCAT))
return -1;
- return type1;
+ return type1 | SDB_TYPE_ARRAY;
}
if ((type1 < 0) || (types_num < type1)
|| (type2 < 0) || (types_num < type2))
return strlen(datum->data.re.raw) + 4;
}
else if (datum->type & SDB_TYPE_ARRAY) {
- /* TODO */
- errno = ENOTSUP;
- return 0;
+ size_t len = 2; /* [] */
+ size_t i;
+ for (i = 0; i < datum->data.array.length; ++i) {
+ sdb_data_t v = SDB_DATA_INIT;
+ sdb_data_array_get(datum, i, &v);
+ len += sdb_data_strlen(&v) + 1;
+ }
+ return len;
}
return 0;
} /* sdb_data_strlen */
@@ -775,14 +844,17 @@ sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
size_t i, pos;
- if ((! datum) || (! buf))
+ if ((! datum) || (! buf) || (! buflen))
return -1;
if (datum->type == SDB_TYPE_INTEGER) {
ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
}
else if (datum->type == SDB_TYPE_DECIMAL) {
- ret = snprintf(buf, buflen, "%g", datum->data.decimal);
+ if (isnan(datum->data.decimal))
+ ret = snprintf(buf, buflen, "nan");
+ else
+ ret = snprintf(buf, buflen, "%g", datum->data.decimal);
}
else if (datum->type == SDB_TYPE_STRING) {
if (! datum->data.string)
}
}
else if (datum->type & SDB_TYPE_ARRAY) {
- /* TODO */
- errno = ENOTSUP;
- return -1;
+ ret = 1;
+ buf[0] = '[';
+ for (i = 0; i < datum->data.array.length; ++i) {
+ sdb_data_t v = SDB_DATA_INIT;
+ int n;
+ if ((size_t)ret >= buflen - 1)
+ break;
+
+ if (ret > 1) {
+ buf[ret] = ',';
+ buf[ret + 1] = ' ';
+ ret += 2;
+ }
+
+ sdb_data_array_get(datum, i, &v);
+ n = sdb_data_format(&v, buf + ret, buflen - ret, quoted);
+ if (n > 0)
+ ret += n;
+ else
+ break;
+ }
+ if ((size_t)ret < buflen - 1) {
+ buf[ret] = ']';
+ buf[ret + 1] = '\0';
+ ++ret;
+ }
}
if (is_null) {