Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| /* | |
| * Written by Alexey Tourbin <at@altlinux.org>. | |
| * | |
| * The author has dedicated the code to the public domain. Anyone is free | |
| * to copy, modify, publish, use, compile, sell, or distribute the original | |
| * code, either in source code form or as a compiled binary, for any purpose, | |
| * commercial or non-commercial, and by any means. | |
| */ | |
| #include <assert.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <pcre.h> | |
| #include <sqlite3ext.h> | |
| SQLITE_EXTENSION_INIT1 | |
| typedef struct { | |
| char *s; | |
| pcre *p; | |
| pcre_extra *e; | |
| } cache_entry; | |
| #ifndef CACHE_SIZE | |
| #define CACHE_SIZE 16 | |
| #endif | |
| static | |
| void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv) | |
| { | |
| const char *re, *str; | |
| pcre *p; | |
| pcre_extra *e; | |
| assert(argc == 2); | |
| re = (const char *) sqlite3_value_text(argv[0]); | |
| if (!re) { | |
| sqlite3_result_error(ctx, "no regexp", -1); | |
| return; | |
| } | |
| str = (const char *) sqlite3_value_text(argv[1]); | |
| if (!str) { | |
| sqlite3_result_error(ctx, "no string", -1); | |
| return; | |
| } | |
| /* simple LRU cache */ | |
| { | |
| int i; | |
| int found = 0; | |
| cache_entry *cache = sqlite3_user_data(ctx); | |
| assert(cache); | |
| for (i = 0; i < CACHE_SIZE && cache[i].s; i++) | |
| if (strcmp(re, cache[i].s) == 0) { | |
| found = 1; | |
| break; | |
| } | |
| if (found) { | |
| if (i > 0) { | |
| cache_entry c = cache[i]; | |
| memmove(cache + 1, cache, i * sizeof(cache_entry)); | |
| cache[0] = c; | |
| } | |
| } | |
| else { | |
| cache_entry c; | |
| const char *err; | |
| int pos; | |
| c.p = pcre_compile(re, 0, &err, &pos, NULL); | |
| if (!c.p) { | |
| char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos); | |
| sqlite3_result_error(ctx, e2, -1); | |
| sqlite3_free(e2); | |
| return; | |
| } | |
| c.e = pcre_study(c.p, 0, &err); | |
| c.s = strdup(re); | |
| if (!c.s) { | |
| sqlite3_result_error(ctx, "strdup: ENOMEM", -1); | |
| pcre_free(c.p); | |
| pcre_free(c.e); | |
| return; | |
| } | |
| i = CACHE_SIZE - 1; | |
| if (cache[i].s) { | |
| free(cache[i].s); | |
| assert(cache[i].p); | |
| pcre_free(cache[i].p); | |
| pcre_free(cache[i].e); | |
| } | |
| memmove(cache + 1, cache, i * sizeof(cache_entry)); | |
| cache[0] = c; | |
| } | |
| p = cache[0].p; | |
| e = cache[0].e; | |
| } | |
| { | |
| int rc; | |
| assert(p); | |
| rc = pcre_exec(p, e, str, strlen(str), 0, 0, NULL, 0); | |
| sqlite3_result_int(ctx, rc >= 0); | |
| return; | |
| } | |
| } | |
| int sqlite3_extension_init(sqlite3 *db, char **err, const sqlite3_api_routines *api) | |
| { | |
| SQLITE_EXTENSION_INIT2(api) | |
| cache_entry *cache = calloc(CACHE_SIZE, sizeof(cache_entry)); | |
| if (!cache) { | |
| *err = "calloc: ENOMEM"; | |
| return 1; | |
| } | |
| sqlite3_create_function(db, "REGEXP", 2, SQLITE_UTF8, cache, regexp, NULL, NULL); | |
| return 0; | |
| } |