Code

plugin: Make sdb_plugin_info_t public.
[sysdb.git] / src / core / data.c
index 1bb5400028223c89eca2f9a10e7ee3e81cc5cb03..dc2d0ae8afde4dbb741bc2525444fddad05ed0a8 100644 (file)
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif /* HAVE_CONFIG_H */
+
 #include "core/data.h"
 
 #include <inttypes.h>
 
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -86,47 +91,167 @@ sdb_data_free_datum(sdb_data_t *datum)
 } /* sdb_data_free_datum */
 
 int
-sdb_data_format(sdb_data_t *datum, sdb_strbuf_t *buf)
+sdb_data_cmp(sdb_data_t *d1, sdb_data_t *d2)
+{
+#define CMP_NULL(a, b) \
+       do { \
+               if (!(a) && !(b)) return 0; \
+               if (!(a)) return -1; \
+               if (!(b)) return 1; \
+       } while (0)
+
+       CMP_NULL(d1, d2);
+
+       if (d1->type != d2->type)
+               return -1;
+
+#define CMP(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
+       switch (d1->type) {
+               case SDB_TYPE_INTEGER:
+                       return CMP(d1->data.integer, d2->data.integer);
+               case SDB_TYPE_DECIMAL:
+                       return CMP(d1->data.decimal, d2->data.decimal);
+               case SDB_TYPE_STRING:
+                       CMP_NULL(d1->data.string, d2->data.string);
+                       return strcasecmp(d1->data.string, d2->data.string);
+               case SDB_TYPE_DATETIME:
+                       return CMP(d1->data.datetime, d2->data.datetime);
+               case SDB_TYPE_BINARY:
+               {
+                       int diff;
+
+                       CMP_NULL(d1->data.binary.datum, d2->data.binary.datum);
+
+                       /* on a common prefix, the shorter datum sorts less */
+                       if (d1->data.binary.length < d2->data.binary.length) {
+                               diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
+                                               d1->data.binary.length);
+                               diff = diff ? diff : -1;
+                       }
+                       else if (d1->data.binary.length > d2->data.binary.length) {
+                               diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
+                                               d2->data.binary.length);
+                               diff = diff ? diff : 1;
+                       }
+                       else
+                               diff = memcmp(d1->data.binary.datum, d2->data.binary.datum,
+                                               d1->data.binary.length);
+
+                       return diff;
+               }
+               default:
+                       return -1;
+       }
+#undef CMP
+#undef CMP_NULL
+} /* sdb_data_cmp */
+
+size_t
+sdb_data_strlen(const sdb_data_t *datum)
+{
+       if (! datum)
+               return 0;
+
+       switch (datum->type) {
+               case SDB_TYPE_INTEGER:
+                       /* log(64) */
+                       return 20;
+               case SDB_TYPE_DECIMAL:
+                       /* XXX: -0xN.NNNNNNp+NNN */
+                       return 42;
+               case SDB_TYPE_STRING:
+                       if (! datum->data.string)
+                               return 6; /* "NULL" */
+                       /* 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:
+                       /* "\xNN" */
+                       return 4 * datum->data.binary.length + 2;
+       }
+       return 0;
+} /* sdb_data_strlen */
+
+int
+sdb_data_format(const sdb_data_t *datum, char *buf, size_t buflen, int quoted)
 {
+       char tmp[sdb_data_strlen(datum) + 1];
+       char *data = NULL;
+       int ret = -1;
+
+       size_t i, pos;
+
        if ((! datum) || (! buf))
                return -1;
 
        switch (datum->type) {
                case SDB_TYPE_INTEGER:
-                       sdb_strbuf_append(buf, "%"PRIi64, datum->data.integer);
+                       ret = snprintf(buf, buflen, "%"PRIi64, datum->data.integer);
                        break;
                case SDB_TYPE_DECIMAL:
-                       sdb_strbuf_append(buf, "%a", datum->data.decimal);
+                       ret = snprintf(buf, buflen, "%a", datum->data.decimal);
                        break;
                case SDB_TYPE_STRING:
-                       /* TODO: escape special characters */
-                       sdb_strbuf_append(buf, "\"%s\"", datum->data.string);
+                       if (! datum->data.string)
+                               data = "NULL";
+                       else {
+                               pos = 0;
+                               for (i = 0; i < strlen(datum->data.string); ++i) {
+                                       char byte = datum->data.string[i];
+
+                                       if ((byte == '\\') || (byte == '"')) {
+                                               tmp[pos] = '\\';
+                                               ++pos;
+                                       }
+                                       tmp[pos] = byte;
+                                       ++pos;
+                               }
+                               tmp[pos] = '\0';
+                               data = tmp;
+                       }
                        break;
                case SDB_TYPE_DATETIME:
-                       {
-                               char tmp[64];
-                               if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
-                                                       datum->data.datetime))
-                                       return -1;
-                               tmp[sizeof(tmp) - 1] = '\0';
-                               sdb_strbuf_append(buf, "%s", tmp);
-                       }
+                       if (! sdb_strftime(tmp, sizeof(tmp), "%F %T %z",
+                                               datum->data.datetime))
+                               return -1;
+                       tmp[sizeof(tmp) - 1] = '\0';
+                       data = tmp;
                        break;
                case SDB_TYPE_BINARY:
-                       {
-                               size_t i;
-                               /* TODO: improve this! */
-                               sdb_strbuf_append(buf, "%s", "\"");
-                               for (i = 0; i < datum->data.binary.length; ++i)
-                                       sdb_strbuf_append(buf, "\\%x",
-                                                       (int)datum->data.binary.datum[i]);
-                               sdb_strbuf_append(buf, "%s", "\"");
+                       pos = 0;
+                       for (i = 0; i < datum->data.binary.length; ++i) {
+                               int byte = (int)datum->data.binary.datum[i];
+                               char hex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                       '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+                               tmp[pos] = '\\';
+                               tmp[pos + 1] = 'x';
+                               pos += 2;
+
+                               if (byte > 0xf) {
+                                       tmp[pos] = hex[byte >> 4];
+                                       ++pos;
+                               }
+                               tmp[pos] = hex[byte & 0xf];
+                               ++pos;
                        }
+                       tmp[pos] = '\0';
+                       data = tmp;
                        break;
-               default:
-                       return -1;
        }
-       return 0;
+
+       if (data) {
+               if (quoted == SDB_UNQUOTED)
+                       ret = snprintf(buf, buflen, "%s", data);
+               else if (quoted == SDB_SINGLE_QUOTED)
+                       ret = snprintf(buf, buflen, "'%s'", data);
+               else
+                       ret = snprintf(buf, buflen, "\"%s\"", data);
+       }
+       buf[buflen - 1] = '\0';
+       return ret;
 } /* sdb_data_format */
 
 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */