Code

data: Fixed length of newly allocated array in concat().
[sysdb.git] / src / core / data.c
1 /*
2  * SysDB - src/core/data.c
3  * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #if HAVE_CONFIG_H
29 #       include "config.h"
30 #endif /* HAVE_CONFIG_H */
32 #include "sysdb.h"
34 #include "core/data.h"
35 #include "utils/error.h"
37 #include <assert.h>
39 #include <errno.h>
41 #include <inttypes.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
47 #include <math.h>
49 /*
50  * private helper functions
51  */
53 /* this function supports in-place copies */
54 static int
55 copy_array_values(sdb_data_t *dst, const sdb_data_t *src, size_t elem_size)
56 {
57         int type = src->type & 0xff;
59         if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)) {
60                 if (dst != src)
61                         memcpy(dst->data.array.values, src->data.array.values,
62                                         src->data.array.length * elem_size);
63         }
64         else if (type == SDB_TYPE_STRING) {
65                 char **s = src->data.array.values;
66                 char **d = dst->data.array.values;
67                 size_t i;
69                 for (i = 0; i < src->data.array.length; ++i) {
70                         d[i] = strdup(s[i]);
71                         if (! d[i])
72                                 return -1;
73                 }
74         }
75         else {
76                 /* TODO */
77                 errno = ENOTSUP;
78                 return -1;
79         }
80         return 0;
81 } /* copy_array_values */
83 static void
84 free_array_values(sdb_data_t *datum)
85 {
86         int type = datum->type & 0xff;
88         if (type == SDB_TYPE_STRING) {
89                 char **v = datum->data.array.values;
90                 size_t i;
92                 for (i = 0; i < datum->data.array.length; ++i) {
93                         if (v[i])
94                                 free(v[i]);
95                         v[i] = NULL;
96                 }
97         }
98 } /* free_array_values */
100 /* Calculate the linear function 'd1 + n * d2'. */
101 static int
102 data_lin(const sdb_data_t *d1, int n, const sdb_data_t *d2, sdb_data_t *res)
104         if (d1->type != d2->type)
105                 return -1;
107         if (d1->type == SDB_TYPE_INTEGER)
108                 res->data.integer = d1->data.integer + (int64_t)n * d2->data.integer;
109         else if (d1->type == SDB_TYPE_DECIMAL)
110                 res->data.decimal = d1->data.decimal + (double)n * d2->data.decimal;
111         else if (d1->type ==  SDB_TYPE_DATETIME)
112                 res->data.datetime = d1->data.datetime + (sdb_time_t)n * d2->data.datetime;
113         else
114                 return -1;
115         res->type = d1->type;
116         return 0;
117 } /* data_lin */
119 /* Multiply d1 with d2. */
120 static int
121 data_mul(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
123         if (d1->type == SDB_TYPE_INTEGER) {
124                 if (d2->type == SDB_TYPE_INTEGER)
125                         res->data.integer = d1->data.integer * d2->data.integer;
126                 else if (d2->type == SDB_TYPE_DATETIME) {
127                         res->data.datetime = (sdb_time_t)d1->data.integer
128                                 * d2->data.datetime;
129                         res->type = SDB_TYPE_DATETIME;
130                         return 0;
131                 }
132                 else
133                         return -1;
134         }
135         else if (d1->type == SDB_TYPE_DECIMAL) {
136                 if (d2->type == SDB_TYPE_DECIMAL)
137                         res->data.decimal = d1->data.decimal * d2->data.decimal;
138                 else if (d2->type == SDB_TYPE_DATETIME) {
139                         res->data.datetime = (sdb_time_t)(d1->data.decimal
140                                         * (double)d2->data.datetime);
141                         res->type = SDB_TYPE_DATETIME;
142                         return 0;
143                 }
144                 else
145                         return -1;
146         }
147         else if (d1->type == SDB_TYPE_DATETIME) {
148                 if (d2->type == SDB_TYPE_DATETIME)
149                         res->data.datetime = d1->data.datetime
150                                 * d2->data.datetime;
151                 else if (d2->type == SDB_TYPE_INTEGER)
152                         res->data.datetime = d1->data.datetime
153                                 * (sdb_time_t)d2->data.integer;
154                 else if (d2->type == SDB_TYPE_DECIMAL)
155                         res->data.datetime = (sdb_time_t)((double)d1->data.datetime
156                                         * d2->data.decimal);
157                 else
158                         return -1;
159         }
160         else
161                 return -1;
163         res->type = d1->type;
164         return 0;
165 } /* data_mul */
167 /* Device d1 by d2 and return the result and the remainder. */
168 static int
169 data_div(const sdb_data_t *d1, const sdb_data_t *d2,
170                 sdb_data_t *res, sdb_data_t *rem)
172         if (d1->type == SDB_TYPE_INTEGER) {
173                 if (d2->type != SDB_TYPE_INTEGER)
174                         return -1;
175                 if (res)
176                         res->data.integer = d1->data.integer / d2->data.integer;
177                 if (rem)
178                         rem->data.integer = d1->data.integer % d2->data.integer;
179         }
180         else if (d1->type == SDB_TYPE_DECIMAL) {
181                 if (d2->type != SDB_TYPE_DECIMAL)
182                         return -1;
183                 if (res)
184                         res->data.decimal = d1->data.decimal / d2->data.decimal;
185                 if (rem)
186                         rem->data.decimal = fmod(d1->data.decimal, d2->data.decimal);
187         }
188         else if (d1->type == SDB_TYPE_DATETIME) {
189                 if (d2->type == SDB_TYPE_DECIMAL) {
190                         if (res)
191                                 res->data.datetime = (sdb_time_t)((double)d1->data.datetime
192                                                 / d2->data.decimal);
193                         if (rem) {
194                                 double tmp = fmod((double)d1->data.datetime, d2->data.decimal);
195                                 rem->data.datetime = (sdb_time_t)tmp;
196                         }
197                 }
198                 else {
199                         sdb_time_t a, b;
200                         if (d2->type == SDB_TYPE_DATETIME) {
201                                 a = d1->data.datetime;
202                                 b = d2->data.datetime;
203                         }
204                         else if (d2->type == SDB_TYPE_INTEGER) {
205                                 a = d1->data.datetime;
206                                 b = (sdb_time_t)d2->data.integer;
207                         }
208                         else
209                                 return -1;
210                         if (res)
211                                 res->data.datetime = a / b;
212                         if (rem)
213                                 rem->data.datetime = a % b;
214                 }
215         }
216         else
217                 return -1;
219         if (res)
220                 res->type = d1->type;
221         if (rem)
222                 rem->type = d1->type;
223         return 0;
224 } /* data_div */
226 /* Concatenate d1 and d2. */
227 static int
228 data_concat(const sdb_data_t *d1, const sdb_data_t *d2, sdb_data_t *res)
230         unsigned char *new;
231         unsigned char *s1, *s2;
232         size_t len1, len2;
234         /* TODO: support array plus element */
235         if (d1->type != d2->type)
236                 return -1;
238         if (d1->type == SDB_TYPE_STRING) {
239                 s1 = (unsigned char *)d1->data.string;
240                 s2 = (unsigned char *)d2->data.string;
241                 len1 = s1 ? strlen((char *)s1) : 0;
242                 len2 = s2 ? strlen((char *)s2) : 0;
243         }
244         else if (d1->type == SDB_TYPE_BINARY) {
245                 s1 = d1->data.binary.datum;
246                 s2 = d2->data.binary.datum;
247                 len1 = d1->data.binary.length;
248                 len2 = d2->data.binary.length;
249         }
250         else if (d1->type & SDB_TYPE_ARRAY) {
251                 size_t elem_size = sdb_data_sizeof(d1->type & 0xff);
252                 s1 = (unsigned char *)d1->data.array.values;
253                 s2 = (unsigned char *)d2->data.array.values;
254                 len1 = d1->data.array.length * elem_size;
255                 len2 = d2->data.array.length * elem_size;
256         }
257         else
258                 return -1;
260         assert(s1 && s2);
262         new = malloc(len1 + len2 + 1);
263         if (! new)
264                 return -1;
266         if (len1)
267                 memcpy(new, s1, len1);
268         if (len2)
269                 memcpy(new + len1, s2, len2);
270         new[len1 + len2] = '\0';
272         res->type = d1->type;
273         if (res->type == SDB_TYPE_STRING) {
274                 res->data.string = (char *)new;
275         }
276         else if (res->type == SDB_TYPE_BINARY) {
277                 res->data.binary.datum = new;
278                 res->data.binary.length = len1 + len2;
279         }
280         else if (d1->type & SDB_TYPE_ARRAY) {
281                 res->data.array.values = new;
282                 res->data.array.length = d1->data.array.length + d2->data.array.length;
283                 if (copy_array_values(res, res, sdb_data_sizeof(res->type & 0xff))) {
284                         /* this leaks already copied values but there's not much we can
285                          * do and this should only happen if we're in trouble anyway */
286                         free(new);
287                         res->data.array.values = NULL;
288                         res->data.array.length = 0;
289                         return -1;
290                 }
291         }
292         return 0;
293 } /* data_concat */
295 /*
296  * public API
297  */
299 const sdb_data_t SDB_DATA_NULL = SDB_DATA_INIT;
301 int
302 sdb_data_copy(sdb_data_t *dst, const sdb_data_t *src)
304         sdb_data_t tmp;
306         if ((! dst) || (! src))
307                 return -1;
309         tmp = *src;
310         if (src->type == SDB_TYPE_STRING) {
311                 if (src->data.string) {
312                         tmp.data.string = strdup(src->data.string);
313                         if (! tmp.data.string)
314                                 return -1;
315                 }
316         }
317         else if (src->type == SDB_TYPE_BINARY) {
318                 if (src->data.binary.datum) {
319                         tmp.data.binary.datum = malloc(src->data.binary.length);
320                         if (! tmp.data.binary.datum)
321                                 return -1;
322                         memcpy(tmp.data.binary.datum, src->data.binary.datum,
323                                         src->data.binary.length);
324                 }
325         }
326         else if (src->type == SDB_TYPE_REGEX) {
327                 if (src->data.re.raw) {
328                         tmp.data.re.raw = strdup(src->data.re.raw);
329                         if (! tmp.data.re.raw)
330                                 return -1;
331                         /* we need to recompile because the regex might point to
332                          * dynamically allocated memory */
333                         if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
334                                                 REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
335                                 free(tmp.data.re.raw);
336                                 return -1;
337                         }
338                 }
339                 else
340                         memset(&tmp.data.re.regex, 0, sizeof(tmp.data.re.regex));
341         }
342         else if (src->type & SDB_TYPE_ARRAY) {
343                 if (src->data.array.values) {
344                         size_t elem_size = sdb_data_sizeof(src->type & 0xff);
345                         tmp.data.array.values = calloc(src->data.array.length, elem_size);
346                         if (! tmp.data.array.values)
347                                 return -1;
348                         if (copy_array_values(&tmp, src, elem_size)) {
349                                 sdb_data_free_datum(&tmp);
350                                 return -1;
351                         }
352                 }
353         }
355         sdb_data_free_datum(dst);
356         *dst = tmp;
357         return 0;
358 } /* sdb_data_copy */
360 void
361 sdb_data_free_datum(sdb_data_t *datum)
363         if (! datum)
364                 return;
366         if (datum->type == SDB_TYPE_STRING) {
367                 if (datum->data.string)
368                         free(datum->data.string);
369                 datum->data.string = NULL;
370         }
371         else if (datum->type == SDB_TYPE_BINARY) {
372                 if (datum->data.binary.datum)
373                         free(datum->data.binary.datum);
374                 datum->data.binary.datum = NULL;
375                 datum->data.binary.length = 0;
376         }
377         else if (datum->type == SDB_TYPE_REGEX) {
378                 if (datum->data.re.raw) {
379                         free(datum->data.re.raw);
380                         regfree(&datum->data.re.regex);
381                 }
382                 datum->data.re.raw = NULL;
383                 memset(&datum->data.re.regex, 0, sizeof(datum->data.re.regex));
384         }
385         else if (datum->type & SDB_TYPE_ARRAY) {
386                 free_array_values(datum);
387                 if (datum->data.array.values)
388                         free(datum->data.array.values);
389                 datum->data.array.values = NULL;
390                 datum->data.array.length = 0;
391         }
392 } /* sdb_data_free_datum */
394 int
395 sdb_data_cmp(const sdb_data_t *d1, const sdb_data_t *d2)
397 #define CMP_NULL(a, b) \
398         do { \
399                 if (!(a) && !(b)) return 0; \
400                 if (!(a)) return -1; \
401                 if (!(b)) return 1; \
402         } while (0)
404         CMP_NULL(d1, d2);
406         if (d1->type != d2->type)
407                 return SDB_CMP(d1->type, d2->type);
409         if (d1->type == SDB_TYPE_INTEGER)
410                 return SDB_CMP(d1->data.integer, d2->data.integer);
411         else if (d1->type == SDB_TYPE_DECIMAL)
412                 return SDB_CMP(d1->data.decimal, d2->data.decimal);
413         else if (d1->type == SDB_TYPE_STRING) {
414                 CMP_NULL(d1->data.string, d2->data.string);
415                 return strcasecmp(d1->data.string, d2->data.string);
416         }
417         else if (d1->type == SDB_TYPE_DATETIME)
418                 return SDB_CMP(d1->data.datetime, d2->data.datetime);
419         else if (d1->type == SDB_TYPE_BINARY) {
420                 int diff;
422                 CMP_NULL(d1->data.binary.datum, d2->data.binary.datum);
424                 /* on a common prefix, the shorter datum sorts less */
425                 if (d1->data.binary.length < d2->data.binary.length) {
426                         diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
427                                         d1->data.binary.length);
428                         diff = diff ? diff : -1;
429                 }
430                 else if (d1->data.binary.length > d2->data.binary.length) {
431                         diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
432                                         d2->data.binary.length);
433                         diff = diff ? diff : 1;
434                 }
435                 else
436                         diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
437                                         d1->data.binary.length);
439                 return diff;
440         }
441         else if (d1->type == SDB_TYPE_REGEX) {
442                 CMP_NULL(d1->data.re.raw, d2->data.re.raw);
443                 return strcmp(d1->data.re.raw, d2->data.re.raw);
444         }
445         else if (d1->type & SDB_TYPE_ARRAY) {
446                 /* TODO */
447                 errno = ENOTSUP;
448                 return -1;
449         }
450         return -1;
451 } /* sdb_data_cmp */
453 int
454 sdb_data_strcmp(const sdb_data_t *d1, const sdb_data_t *d2)
456         char d1_str[sdb_data_strlen(d1) + 1];
457         char d2_str[sdb_data_strlen(d2) + 1];
459         if ((d1->type & SDB_TYPE_ARRAY) || (d2->type & SDB_TYPE_ARRAY)) {
460                 /* TODO */
461                 errno = ENOTSUP;
462                 return -1;
463         }
465         if (sdb_data_isnull(d1))
466                 d1 = NULL;
467         if (sdb_data_isnull(d2))
468                 d2 = NULL;
470         CMP_NULL(d1, d2);
472         if (sdb_data_format(d1, d1_str, sizeof(d1_str), SDB_UNQUOTED) < 0)
473                 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
474         if (sdb_data_format(d2, d2_str, sizeof(d2_str), SDB_UNQUOTED) < 0)
475                 return SDB_CMP(sizeof(d1_str), sizeof(d2_str));
477         return strcasecmp(d1_str, d2_str);
478 #undef CMP_NULL
479 } /* sdb_data_strcmp */
481 _Bool
482 sdb_data_isnull(const sdb_data_t *datum)
484         if (! datum)
485                 return 1;
486         if (datum->type == SDB_TYPE_NULL)
487                 return 1;
488         if ((datum->type == SDB_TYPE_STRING) && (! datum->data.string))
489                 return 1;
490         if ((datum->type == SDB_TYPE_BINARY) && (! datum->data.binary.datum))
491                 return 1;
492         if ((datum->type == SDB_TYPE_REGEX) && (! datum->data.re.raw))
493                 return 1;
494         if ((datum->type & SDB_TYPE_ARRAY) && (! datum->data.array.values))
495                 return 1;
496         return 0;
497 } /* sdb_data_isnull */
499 int
500 sdb_data_parse_op(const char *op)
502         if (! strcmp(op, "+"))
503                 return SDB_DATA_ADD;
504         else if (! strcmp(op, "-"))
505                 return SDB_DATA_SUB;
506         else if (! strcmp(op, "*"))
507                 return SDB_DATA_MUL;
508         else if (! strcmp(op, "/"))
509                 return SDB_DATA_DIV;
510         else if (! strcmp(op, "%"))
511                 return SDB_DATA_MOD;
512         else if (! strcmp(op, "||"))
513                 return SDB_DATA_CONCAT;
514         return -1;
515 } /* sdb_data_parse_op */
517 int
518 sdb_data_expr_eval(int op, const sdb_data_t *d1, const sdb_data_t *d2,
519                 sdb_data_t *res)
521         if ((! d1) || (! d2) || (! res))
522                 return -1;
523         if (sdb_data_isnull(d1) || sdb_data_isnull(d2)) {
524                 *res = SDB_DATA_NULL;
525                 return 0;
526         }
527         switch (op) {
528                 case SDB_DATA_CONCAT:
529                         return data_concat(d1, d2, res);
530                 case SDB_DATA_ADD:
531                         return data_lin(d1, 1, d2, res);
532                 case SDB_DATA_SUB:
533                         return data_lin(d1, -1, d2, res);
534                 case SDB_DATA_MUL:
535                         return data_mul(d1, d2, res);
536                 case SDB_DATA_DIV:
537                         return data_div(d1, d2, res, NULL);
538                 case SDB_DATA_MOD:
539                         return data_div(d1, d2, NULL, res);
540         }
541         return -1;
542 } /* sdb_data_expr_eval */
544 size_t
545 sdb_data_strlen(const sdb_data_t *datum)
547         if (! datum)
548                 return 0;
550         if (datum->type == SDB_TYPE_INTEGER) {
551                 /* log(64) */
552                 return 20;
553         }
554         else if (datum->type == SDB_TYPE_DECIMAL) {
555                 /* XXX: -d.dddddde+dd or -ddddd.dddddd */
556                 return 42;
557         }
558         else if (datum->type == SDB_TYPE_STRING) {
559                 if (! datum->data.string)
560                         return 8; /* "<NULL>" */
561                 /* in the worst case, each character needs to be escaped */
562                 return 2 * strlen(datum->data.string) + 2;
563         }
564         else if (datum->type == SDB_TYPE_DATETIME) {
565                 /* "YYYY-MM-DD HH:MM:SS +zzzz" */
566                 return 27;
567         }
568         else if (datum->type == SDB_TYPE_BINARY) {
569                 if (! datum->data.binary.datum)
570                         return 8; /* "<NULL>" */
571                 /* "\xNN" */
572                 return 4 * datum->data.binary.length + 2;
573         }
574         else if (datum->type == SDB_TYPE_REGEX) {
575                 if (! datum->data.re.raw)
576                         return 8; /* "<NULL>" */
577                 /* "/.../" */
578                 return strlen(datum->data.re.raw) + 4;
579         }
580         else if (datum->type & SDB_TYPE_ARRAY) {
581                 /* TODO */
582                 errno = ENOTSUP;
583                 return 0;
584         }
585         return 0;
586 } /* sdb_data_strlen */
588 int
589 sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
591         char tmp[sdb_data_strlen(datum) + 1];
592         char *data = NULL;
593         int ret = -1;
595         size_t i, pos;
597         if ((! datum) || (! buf))
598                 return -1;
600         if (datum->type == SDB_TYPE_INTEGER) {
601                 ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
602         }
603         else if (datum->type == SDB_TYPE_DECIMAL) {
604                 ret = snprintf(buf, buflen, "%g", datum->data.decimal);
605         }
606         else if (datum->type == SDB_TYPE_STRING) {
607                 if (! datum->data.string)
608                         data = "<NULL>";
609                 else {
610                         pos = 0;
611                         for (i = 0; i < strlen(datum->data.string); ++i) {
612                                 char byte = datum->data.string[i];
614                                 if ((byte == '\\') || (byte == '"')) {
615                                         tmp[pos] = '\\';
616                                         ++pos;
617                                 }
618                                 tmp[pos] = byte;
619                                 ++pos;
620                         }
621                         tmp[pos] = '\0';
622                         data = tmp;
623                 }
624         }
625         else if (datum->type == SDB_TYPE_DATETIME) {
626                 if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
627                                         datum->data.datetime))
628                         return -1;
629                 tmp[sizeof(tmp) - 1] = '\0';
630                 data = tmp;
631         }
632         else if (datum->type == SDB_TYPE_BINARY) {
633                 pos = 0;
634                 for (i = 0; i < datum->data.binary.length; ++i) {
635                         int byte = (int)datum->data.binary.datum[i];
636                         char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
637                                 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
639                         tmp[pos] = '\\';
640                         tmp[pos + 1] = 'x';
641                         pos += 2;
643                         if (byte > 0xf) {
644                                 tmp[pos] = hex[byte >> 4];
645                                 ++pos;
646                         }
647                         tmp[pos] = hex[byte & 0xf];
648                         ++pos;
649                 }
650                 if (datum->data.binary.datum) {
651                         tmp[pos] = '\0';
652                         data = tmp;
653                 }
654                 else
655                         data = "<NULL>";
656         }
657         else if (datum->type == SDB_TYPE_REGEX) {
658                 if (! datum->data.re.raw)
659                         data = "<NULL>";
660                 else {
661                         snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw);
662                         data = tmp;
663                 }
664         }
665         else if (datum->type & SDB_TYPE_ARRAY) {
666                 /* TODO */
667                 errno = ENOTSUP;
668                 return -1;
669         }
671         if (data) {
672                 if (quoted == SDB_UNQUOTED)
673                         ret = snprintf(buf, buflen, "%s", data);
674                 else if (quoted == SDB_SINGLE_QUOTED)
675                         ret = snprintf(buf, buflen, "'%s'", data);
676                 else
677                         ret = snprintf(buf, buflen, "\"%s\"", data);
678         }
679         buf[buflen - 1] = '\0';
680         return ret;
681 } /* sdb_data_format */
683 int
684 sdb_data_parse(char *str, int type, sdb_data_t *data)
686         sdb_data_t tmp;
688         char *endptr = NULL;
690         errno = 0;
691         if (type == SDB_TYPE_INTEGER) {
692                 tmp.data.integer = strtoll(str, &endptr, 0);
693         }
694         else if (type == SDB_TYPE_DECIMAL) {
695                 tmp.data.decimal = strtod(str, &endptr);
696         }
697         else if (type == SDB_TYPE_STRING) {
698                 tmp.data.string = str;
699         }
700         else if (type == SDB_TYPE_DATETIME) {
701                 double datetime = strtod(str, &endptr);
702                 tmp.data.datetime = DOUBLE_TO_SDB_TIME(datetime);
703         }
704         else if (type == SDB_TYPE_BINARY) {
705                 /* we don't support any binary information containing 0-bytes */
706                 tmp.data.binary.length = strlen(str);
707                 tmp.data.binary.datum = (unsigned char *)str;
708         }
709         else if (type == SDB_TYPE_REGEX) {
710                 tmp.data.re.raw = strdup(str);
711                 if (! tmp.data.re.raw)
712                         return -1;
713                 if (regcomp(&tmp.data.re.regex, tmp.data.re.raw,
714                                         REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
715                         sdb_log(SDB_LOG_ERR, "core: Failed to compile regular "
716                                         "expression '%s'", tmp.data.re.raw);
717                         free(tmp.data.re.raw);
718                         return -1;
719                 }
720                 if (! data) {
721                         tmp.type = SDB_TYPE_REGEX;
722                         sdb_data_free_datum(&tmp);
723                 }
724         }
725         else if (type & SDB_TYPE_ARRAY) {
726                 /* TODO */
727                 errno = ENOTSUP;
728                 return -1;
729         }
730         else {
731                 errno = EINVAL;
732                 return -1;
733         }
735         if ((type == SDB_TYPE_INTEGER) || (type == SDB_TYPE_DECIMAL)
736                         || (type == SDB_TYPE_DATETIME)) {
737                 if (errno || (str == endptr)) {
738                         char errbuf[1024];
739                         sdb_log(SDB_LOG_ERR, "core: Failed to parse string "
740                                         "'%s' as numeric value (type %i): %s", str, type,
741                                         sdb_strerror(errno, errbuf, sizeof(errbuf)));
742                         return -1;
743                 }
744                 else if (endptr && (*endptr != '\0'))
745                         sdb_log(SDB_LOG_WARNING, "core: Ignoring garbage after "
746                                         "number while parsing numeric value (type %i): %s.",
747                                         type, endptr);
748         }
750         if (data) {
751                 *data = tmp;
752                 data->type = type;
753         }
754         return 0;
755 } /* sdb_data_parse */
757 size_t
758 sdb_data_sizeof(int type)
760         sdb_data_t v;
761         if (type == SDB_TYPE_INTEGER)
762                 return sizeof(v.data.integer);
763         else if (type == SDB_TYPE_DECIMAL)
764                 return sizeof(v.data.decimal);
765         else if (type == SDB_TYPE_STRING)
766                 return sizeof(v.data.string);
767         else if (type == SDB_TYPE_DATETIME)
768                 return sizeof(v.data.datetime);
769         else if (type == SDB_TYPE_BINARY)
770                 return sizeof(v.data.binary);
771         else if (type == SDB_TYPE_REGEX)
772                 return sizeof(v.data.re);
773         return 0;
774 } /* sdb_data_sizeof */
776 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */