diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-18 00:04:51 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-18 00:04:51 +0200 |
commit | 8c4ab07dbf003ba07bec6e77fd803b9c54b91e52 (patch) | |
tree | 9f4e1b0dcd3f10e78c815d6c5baecc8da8ad1c47 /src/builtin.c | |
parent | 317095181674a01651602ddf6817e888d0ad5280 (diff) | |
download | wydawca-8c4ab07dbf003ba07bec6e77fd803b9c54b91e52.tar.gz wydawca-8c4ab07dbf003ba07bec6e77fd803b9c54b91e52.tar.bz2 |
Various fixes
Diffstat (limited to 'src/builtin.c')
-rw-r--r-- | src/builtin.c | 224 |
1 files changed, 218 insertions, 6 deletions
diff --git a/src/builtin.c b/src/builtin.c index 9786383..711694f 100644 --- a/src/builtin.c +++ b/src/builtin.c @@ -16,6 +16,11 @@ #include "wydawca.h" #include "builtin.h" +#include "fnmatch.h" +#include "regex.h" +#define obstack_chunk_alloc malloc +#define obstack_chunk_free free +#include "obstack.h" int builtin_init (struct access_method *meth) @@ -35,11 +40,219 @@ builtin_open (struct access_method *meth) return meth; } +#define CMP_EXACT 0 +#define CMP_FNMATCH 1 +#define CMP_REGEX 2 + +#define RF_ICASE 0x1 +#define RF_BASIC 0x2 + +#define STRMATCH(s, p, len) \ + (len == sizeof(s) - 1 && memcmp (s, p, sizeof(s) - 1) == 0) + +typedef int (*strcmp_fn) (const char *, const char *, int flags); + +static int +cmp_exact (const char *pat, const char *str, int flags) +{ + return strcmp (pat, str) == 0; +} + +static int +cmp_exact_ci (const char *pat, const char *str, int flags) +{ + return strcmp (pat, str) == 0; +} + +static int +cmp_fnmatch (const char *pat, const char *str, int flags) +{ + return fnmatch (pat, str, flags) == 0; +} + +static int +cmp_regex (const char *pat, const char *str, int flags) +{ + int rc; + regex_t regex; + + rc = regcomp (®ex, pat, flags); + if (rc) + { + char errbuf[512]; + + regerror (rc, ®ex, errbuf, sizeof (errbuf)); + logmsg (LOG_ERR, "%s: cannot compile regexp: %s", pat, errbuf); + return 0; + } + + rc = regexec (®ex, str, 0, NULL, 0); + regfree (®ex); + return rc == 0; +} + +int +parse_cmp_type (const char *pat, strcmp_fn *cmpfn, int *rf) +{ + size_t len = strcspn (pat, ","); + int flags = 0; + int cmp; + + if (STRMATCH ("exact", pat, len)) + cmp = CMP_EXACT; + else if (STRMATCH ("fnmatch", pat, len)) + cmp = CMP_FNMATCH; + else if (STRMATCH ("regex", pat, len)) + cmp = CMP_REGEX; + else + return 1; + + pat += len; + if (*pat) + { + while (*++pat) + { + switch (*pat) + { + case 'i': + flags |= RF_ICASE; + break; + + case 'b': + flags |= RF_BASIC; + break; + + default: + logmsg (LOG_NOTICE, "unrecognized comparison flag: %c", *pat); + } + } + } + + switch (cmp) + { + case CMP_EXACT: + *cmpfn = (flags & RF_ICASE) ? cmp_exact_ci : cmp_exact; + break; + + case CMP_FNMATCH: + *cmpfn = cmp_fnmatch; + *rf = FNM_NOESCAPE | FNM_PERIOD | + ((flags & RF_ICASE) ? FNM_CASEFOLD : 0); + break; + + case CMP_REGEX: + *cmpfn = cmp_regex; + *rf = ((flags & RF_BASIC) ? 0 : REG_EXTENDED) | REG_NOSUB; + if (flags & RF_ICASE) + *rf |= REG_ICASE; + break; + } + return 0; +} + +struct builtin_data_storage +{ + struct obstack stk; + char **wp; +}; + +static int default_ncol[] = { + 1, /* verify-user: arbitrary return, usually user name */ + 1, /* gpg-key: key */ + 2, /* project-owner: email, realname */ + 2, /* user-data: email, realname */ +}; + int builtin_run (struct access_method *meth, void *handle, const char *req) { - meth->nrow = meth->parmc; - meth->ncol = 1; + int i; + size_t count = 0; + struct obstack stk; + int flags = 0; + strcmp_fn cmpfn = cmp_exact; + struct builtin_data_storage *bds; + int ncol = default_ncol[meth->id]; + + if (meth->parmc == 0) + { + meth->nrow = meth->ncol = 0; + return 0; + } + + obstack_init (&stk); + + for (i = 0; i < meth->parmc; i++) + { + char *pat = meth->parmv[i]; + char *val; + + if (pat[0] == '/') + { + pat++; + if (*pat != '/' && parse_cmp_type (pat, &cmpfn, &flags) == 0) + continue; + } + + if (i + ncol >= meth->parmc) + break; + + if (cmpfn (pat, req, flags)) + { + size_t j; + for (j = 1; j <= ncol; j++) + { + char *val = meth->parmv[i + j]; + obstack_grow (&stk, val, strlen (val) + 1); + } + count++; + } + + i += ncol; + } + + meth->nrow = count; + meth->ncol = ncol; + + if (count == 0) + { + obstack_free (&stk, NULL); + bds = NULL; + } + else + { + size_t i; + char *p; + + bds = xmalloc (sizeof (*bds)); + count *= ncol; + bds->wp = xcalloc (count, sizeof (bds->wp[0])); + bds->stk = stk; + p = obstack_finish (&stk); + + for (i = 0; i < count; i++) + { + bds->wp[i] = p; + p += strlen (p) + 1; + } + } + + meth->storage = bds; + + return 0; +} + +int +builtin_free_result (struct access_method *method, void *handle) +{ + if (method->storage) + { + struct builtin_data_storage *bds = method->storage; + obstack_free (&bds->stk, NULL); + free (bds->wp); + free (bds); + method->storage = NULL; + } return 0; } @@ -47,10 +260,9 @@ int builtin_get (struct access_method *method, void *handle, unsigned nrow, unsigned ncol) { - if (nrow >= method->parmc) - return 1; - method_copy_result (method, method->parmv[nrow], - strlen (method->parmv[nrow])); + struct builtin_data_storage *bds = method->storage; + char *str = bds->wp[nrow * method->ncol + ncol]; + method_copy_result (method, str, strlen (str)); return 0; } |