#include #include #include #include #include "util.h" #include "ctype.h" #include "config.h" #include "structs.h" extern MAP_OPS map_ops_regex; typedef struct map_regex_priv MAP_REGEX_PRIV; struct map_regex_priv { char *sre; regex_t cre; char *repl; int nmatch; regmatch_t *pmatch; } ; /* ord and repl must not throw out */ static void regex_scan_repl(const char *str, void (*ord)(const char *, int), void (*repl)(int)) { int i; int o0; int n; void end_ord(void) { if (o0 >= 0) (*ord)(str+o0,i-o0); o0 = -1; } o0 = -1; for (i=0;str[i];i++) { if (str[i] == '\\') { end_ord(); switch (str[i+1]) { case '\\': o0 = ++i; break; case '0': n = 0; if (0) { case '1': n = 1; } if (0) { case '2': n = 2; } if (0) { case '3': n = 3; } if (0) { case '4': n = 4; } if (0) { case '5': n = 5; } if (0) { case '6': n = 6; } if (0) { case '7': n = 7; } if (0) { case '8': n = 8; } if (0) { case '9': n = 9; } if (0) { case '(': { unsigned long int v; char *ep; n = -1; v = strtoul(str+i+2,&ep,10); if (*ep != ')') { (*ord)("?[no )]",7); i = (ep - str) - 1; } else if (ep == str+i+2) { (*ord)("?[()]",5); i += 2; } else { n = v; if (n != v) { (*ord)("?[range]",8); n = -1; } i = ep - str; } } } if (n >= 0) (*repl)(n); break; default: { char *ebuf; n = asprintf(&ebuf,"?[%02x]",(unsigned char)str[i+1]); (*ord)(ebuf,n); free(ebuf); } break; } } else { if (o0 < 0) o0 = i; } } end_ord(); } static int map_regex_add(CONFIG *cfg, LISTEN *l, const char *key, int keylen, const char *rest) { MAP *map; MAP_REGEX_PRIV *p; char delim; const char *d2; int e; if ((keylen != 5) || bcmp(key,"regex",5)) return(0); delim = rest[0]; if (! delim) config_err(cfg,"missing argument on `map regex' listen line"); d2 = index(rest+1,delim); if (d2 == 0) config_err(cfg,"no second delimiter on `map regex' listen line"); p = malloc(sizeof(MAP_REGEX_PRIV)); p->sre = blk_to_nulterm(rest+1,d2-(rest+1)); e = regcomp(&p->cre,p->sre,REG_EXTENDED); if (e) { char *eb; int ebl; void free_eb(void) { free(eb); } ebl = regerror(e,&p->cre,0,0); eb = malloc(ebl); regerror(e,&p->cre,eb,ebl); /* Do we need to regfree()? Documentation doesn't say. Looking at current implementation, answer is "no", and, indeed, some errors can occur before the regex_t is touched. Assume not. regfree(&p->cre); */ free(p->sre); free(p); config_err_post(&free_eb,cfg,"bad regex on `map regex' listen line: %s",eb); } p->repl = strdup(d2+1); p->nmatch = 0; { void ordinary(const char *s __attribute__((__unused__)), int l __attribute__((__unused__))) { } void replacement(int n) { if (n >= p->nmatch) p->nmatch = n + 1; } regex_scan_repl(p->repl,&ordinary,&replacement); } p->pmatch = malloc(p->nmatch*sizeof(regmatch_t)); map = malloc(sizeof(MAP)); map->ops = &map_ops_regex; map->priv = p; map->link = l->mappings; l->mappings = map; return(1); } static void map_regex_free(void *pv) { MAP_REGEX_PRIV *p; p = pv; free(p->sre); regfree(&p->cre); free(p->repl); free(p->pmatch); free(p); } MAP_OPS map_ops_regex = MAP_OPS_INIT(regex);