/* wydawca - automatic release submission daemon Copyright (C) 2009-2011 Sergey Poznyakoff Wydawca is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Wydawca is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wydawca. If not, see . */ #include "wydawca.h" #include "builtin.h" #ifndef FNM_CASEFOLD # define FNM_CASEFOLD 0 #endif int builtin_init (struct dictionary *dict) { return 0; } int builtin_done (struct dictionary *dict) { return 0; } void * builtin_open (struct dictionary *dict) { return dict; } #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 txtacc *acc; char **wp; }; static int default_ncol[] = { 4, /* project-uploader: name, realname, email, pubkey */ 2, /* project-owner: email, realname */ }; int builtin_lookup (struct dictionary *dict, void *handle, const char *req) { int i; int rc; size_t count = 0; struct txtacc *acc; int flags = 0; strcmp_fn cmpfn = cmp_exact; struct builtin_data_storage *bds; int ncol = default_ncol[dict->id]; if (dict->parmc == 0) { dict->nrow = dict->ncol = 0; return 0; } acc = txtacc_create (); for (i = 0; i < dict->parmc; i++) { char *pat = dict->parmv[i]; if (pat[0] == '/') { pat++; if (*pat != '/' && parse_cmp_type (pat, &cmpfn, &flags) == 0) continue; } if (i + ncol >= dict->parmc) break; if (cmpfn (pat, req, flags)) { size_t j; for (j = 1; j <= ncol; j++) { char *val = dict->parmv[i + j]; txtacc_grow (acc, val, strlen (val) + 1); } count++; } i += ncol; } dict->nrow = count; dict->ncol = ncol; if (count == 0) { txtacc_free (acc); bds = NULL; rc = 1; } else { size_t i; char *p; bds = grecs_malloc (sizeof (*bds)); count *= ncol; bds->wp = grecs_calloc (count, sizeof (bds->wp[0])); bds->acc = acc; p = txtacc_finish (acc, 0); for (i = 0; i < count; i++) { bds->wp[i] = p; p += strlen (p) + 1; } rc = 0; } dict->storage = bds; return rc; } int builtin_free_result (struct dictionary *dict, void *handle) { if (dict->storage) { struct builtin_data_storage *bds = dict->storage; txtacc_free (bds->acc); free (bds->wp); free (bds); dict->storage = NULL; } return 0; } int builtin_get (struct dictionary *dict, void *handle, unsigned nrow, unsigned ncol) { struct builtin_data_storage *bds = dict->storage; char *str = bds->wp[nrow * dict->ncol + ncol]; dictionary_copy_result (dict, str, strlen (str)); return 0; }