summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 8a5c485)
raw | patch | inline | side by side (parent: 8a5c485)
author | Sebastian Harl <sh@tokkee.org> | |
Tue, 7 Oct 2014 19:41:54 +0000 (21:41 +0200) | ||
committer | Sebastian Harl <sh@tokkee.org> | |
Tue, 7 Oct 2014 19:41:54 +0000 (21:41 +0200) |
This type may be used to store the raw and compiled regex in a datum and use
regexes in all places in which a generic value may be used. It does not
support any arithmetic or concatenation operations.
regexes in all places in which a generic value may be used. It does not
support any arithmetic or concatenation operations.
src/core/data.c | patch | blob | history | |
src/include/core/data.h | patch | blob | history | |
t/unit/core/data_test.c | patch | blob | history |
diff --git a/src/core/data.c b/src/core/data.c
index 9031f03d8a88d4dbd4154c4f55d9400f427c1f30..2a8c439e08c7da72dca03ce9b28e0c59413e36b2 100644 (file)
--- a/src/core/data.c
+++ b/src/core/data.c
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;
}
sdb_data_free_datum(dst);
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 */
return diff;
}
+ case SDB_TYPE_REGEX:
+ CMP_NULL(d1->data.re.raw, d2->data.re.raw);
+ return strcmp(d1->data.re.raw, d2->data.re.raw);
}
return -1;
} /* sdb_data_cmp */
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 */
return 8; /* "<NULL>" */
/* "\xNN" */
return 4 * datum->data.binary.length + 2;
+ case SDB_TYPE_REGEX:
+ if (! datum->data.re.raw)
+ return 8; /* "<NULL>" */
+ /* "/.../" */
+ return strlen(datum->data.re.raw) + 4;
}
return 0;
} /* sdb_data_strlen */
else
data = "<NULL>";
break;
+ case SDB_TYPE_REGEX:
+ if (! datum->data.re.raw)
+ data = "<NULL>";
+ else {
+ snprintf(tmp, sizeof(tmp), "/%s/", datum->data.re.raw);
+ data = tmp;
+ }
+ break;
}
if (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, str,
+ REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
+ free(tmp.data.re.raw);
+ sdb_log(SDB_LOG_ERR, "core: Failed to compile regular "
+ "expression '%s'", str);
+ return -1;
+ }
+ if (! data) {
+ tmp.type = SDB_TYPE_REGEX;
+ sdb_data_free_datum(&tmp);
+ }
+ break;
default:
errno = EINVAL;
return -1;
index 1bd0d5354e652656b891d0178cdf5030bf4992ec..a81cea45b5b6e5f52d5c6ba671f5b2ae42aa1e3c 100644 (file)
--- a/src/include/core/data.h
+++ b/src/include/core/data.h
#include <inttypes.h>
#include <stddef.h>
+#include <sys/types.h>
+#include <regex.h>
+
#ifdef __cplusplus
extern "C" {
#endif
SDB_TYPE_STRING,
SDB_TYPE_DATETIME,
SDB_TYPE_BINARY,
+ SDB_TYPE_REGEX,
};
#define SDB_TYPE_TO_STRING(t) \
- (((t) == SDB_TYPE_INTEGER) \
- ? "INTEGER" \
- : ((t) == SDB_TYPE_DECIMAL) \
- ? "DECIMAL" \
- : ((t) == SDB_TYPE_STRING) \
- ? "STRING" \
- : ((t) == SDB_TYPE_DATETIME) \
- ? "DATETIME" \
- : ((t) == SDB_TYPE_BINARY) \
- ? "BINARY" \
- : "UNKNOWN")
+ (((t) == SDB_TYPE_INTEGER) ? "INTEGER" \
+ : ((t) == SDB_TYPE_DECIMAL) ? "DECIMAL" \
+ : ((t) == SDB_TYPE_STRING) ? "STRING" \
+ : ((t) == SDB_TYPE_DATETIME) ? "DATETIME" \
+ : ((t) == SDB_TYPE_BINARY) ? "BINARY" \
+ : ((t) == SDB_TYPE_REGEX) ? "REGEX" : "UNKNOWN")
/*
* sdb_data_t:
size_t length;
unsigned char *datum;
} binary; /* SDB_TYPE_BINARY */
+ struct {
+ char *raw;
+ regex_t regex;
+ } re; /* SDB_TYPE_REGEX */
} data;
} sdb_data_t;
#define SDB_DATA_INIT { 0, { .integer = 0 } }
* specified as (floating point) number of seconds since the epoch. For string
* and binary data, the input string is passed to the datum. The function does
* not allocate new memory for that purpose. Use sdb_data_copy() if you want
- * to do that.
+ * to do that. For regex data, the input string is copied to newly allocated
+ * memory and also compiled to a regex. Use sdb_data_free_datum() to free the
+ * dynamically allocated memory.
*
* Returns:
* - 0 on success
index 636fd13e7523dd403c1ed84f169d494ff0f2cdad..742466eec0008c599824de8c49bb37aacefc3d65 100644 (file)
--- a/t/unit/core/data_test.c
+++ b/t/unit/core/data_test.c
#include "core/data.h"
#include "libsysdb_test.h"
+#include <assert.h>
#include <check.h>
+static regex_t empty_re;
+
START_TEST(test_data)
{
sdb_data_t d1, d2;
"sdb_data_free_datum() didn't reset binary datum length");
fail_unless(d1.data.binary.datum == NULL,
"sdb_data_free_datum() didn't free binary datum");
+
+ check = sdb_data_parse(".", SDB_TYPE_REGEX, &d2);
+ fail_unless(check == 0,
+ "INTERNAL ERROR: Failed to parse regex '.'");
+ assert(d2.type == SDB_TYPE_REGEX);
+ check = sdb_data_copy(&d1, &d2);
+ fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+ fail_unless(d1.type == d2.type,
+ "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+ d1.type, d2.type);
+ fail_unless(d1.data.re.raw != d2.data.re.raw,
+ "sdb_data_copy() copy string pointer");
+ fail_unless(!strcmp(d1.data.re.raw, d2.data.re.raw),
+ "sdb_data_copy() didn't copy raw regex: got: %s; expected: %s",
+ d1.data.re.raw, d2.data.re.raw);
+ sdb_data_free_datum(&d2);
+
+ sdb_data_free_datum(&d1);
+ fail_unless(d1.data.re.raw == NULL,
+ "sdb_data_free_datum() didn't reset raw regex");
+
+ d2.type = SDB_TYPE_REGEX;
+ d2.data.re.raw = NULL;
+ check = sdb_data_copy(&d1, &d2);
+ fail_unless(!check, "sdb_data_copy() = %i; expected: 0", check);
+ fail_unless(d1.type == d2.type,
+ "sdb_data_copy() didn't copy type; got: %i; expected: %i",
+ d1.type, d2.type);
+ fail_unless(d1.data.re.raw == d2.data.re.raw,
+ "sdb_data_copy() didn't copy raw regex: got: %s; expected: %s",
+ d1.data.re.raw, d2.data.re.raw);
+
+ sdb_data_free_datum(&d1);
+ fail_unless(d1.data.re.raw == NULL,
+ "sdb_data_free_datum() didn't reset raw regex");
}
END_TEST
},
1,
},
+ {
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ 0,
+ },
+ {
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
+ -1,
+ },
+ {
+ { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ 1,
+ },
};
size_t i;
},
1,
},
+ {
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ 0,
+ },
+ {
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
+ -1,
+ },
+ {
+ { SDB_TYPE_REGEX, { .re = { "b", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { "a", empty_re } } },
+ 1,
+ },
/* type mismatches */
{
{ SDB_TYPE_INTEGER, { .integer = 123 } },
{ SDB_TYPE_STRING, { .string = "12.0" } },
1,
},
+ {
+ { SDB_TYPE_REGEX, { .re = { "regex", empty_re } } },
+ { SDB_TYPE_STRING, { .string = "/regex/" } },
+ 0,
+ },
};
size_t i;
{ .binary = { 6, (unsigned char *)"a\0ab\0b" } },
},
},
+ {
+ { SDB_TYPE_REGEX, { .re = { ".", empty_re } } },
+ { SDB_TYPE_REGEX, { .re = { ".", empty_re } } },
+ SDB_DATA_INIT,
+ SDB_DATA_INIT,
+ SDB_DATA_INIT,
+ SDB_DATA_INIT,
+ SDB_DATA_INIT,
+ SDB_DATA_INIT,
+ },
/* supported type-mismatches */
{
/* int * datetime */
},
"\"\\x62\\x69\\x6e\\x61\\x72\\x79\\x0\\x63\\x72\\x61\\x70\\x42\"",
},
+ {
+ { SDB_TYPE_REGEX, { .re = { "some regex", empty_re } } },
+ "\"/some regex/\"",
+ },
};
size_t i;
sdb_data_t result;
int expected;
} golden_data[] = {
- { "4711", { SDB_TYPE_INTEGER, { .integer = 4711 } }, 0 },
- { "0x10", { SDB_TYPE_INTEGER, { .integer = 16 } }, 0 },
- { "010", { SDB_TYPE_INTEGER, { .integer = 8 } }, 0 },
- { "abc", { SDB_TYPE_INTEGER, { .integer = 0 } }, -1 },
- { "1.2", { SDB_TYPE_DECIMAL, { .decimal = 1.2 } }, 0 },
- { "0x1p+16", { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, 0 },
- { "abc", { SDB_TYPE_DECIMAL, { .decimal = 0.0 } }, -1 },
- { "abc", { SDB_TYPE_STRING, { .string = "abc" } }, 0 },
- { ".4", { SDB_TYPE_DATETIME, { .datetime = 400000000 } }, 0 },
- { "abc", { SDB_TYPE_DATETIME, { .datetime = 0 } }, -1 },
+ { "4711", { SDB_TYPE_INTEGER, { .integer = 4711 } }, 0 },
+ { "0x10", { SDB_TYPE_INTEGER, { .integer = 16 } }, 0 },
+ { "010", { SDB_TYPE_INTEGER, { .integer = 8 } }, 0 },
+ { "abc", { SDB_TYPE_INTEGER, { .integer = 0 } }, -1 },
+ { "1.2", { SDB_TYPE_DECIMAL, { .decimal = 1.2 } }, 0 },
+ { "0x1p+16", { SDB_TYPE_DECIMAL, { .decimal = 65536.0 } }, 0 },
+ { "abc", { SDB_TYPE_DECIMAL, { .decimal = 0.0 } }, -1 },
+ { "abc", { SDB_TYPE_STRING, { .string = "abc" } }, 0 },
+ { ".4", { SDB_TYPE_DATETIME, { .datetime = 400000000 } }, 0 },
+ { "abc", { SDB_TYPE_DATETIME, { .datetime = 0 } }, -1 },
{ "abc", { SDB_TYPE_BINARY,
{ .binary = { 3, (unsigned char *)"abc" } } }, 0 },
+ { "abc", { SDB_TYPE_REGEX, { .re = { "abc", empty_re } } }, 0 },
+ { "(|", { SDB_TYPE_REGEX, { .re = { "", empty_re } } }, -1 },
};
size_t i;
fail_unless(golden_data[i].input == (char *)result.data.binary.datum,
"sdb_data_parse(%s, %d, <d>) modified input string",
golden_data[i].input, type);
+ if (type == SDB_TYPE_REGEX) {
+ fail_unless(golden_data[i].input != result.data.re.raw,
+ "sdb_data_parse(%s, %d, <d>) copied input string",
+ golden_data[i].input, type);
+ sdb_data_free_datum(&result);
+ }
}
}
END_TEST