/* MiddleMan filtering proxy server Copyright (C) 2002 Jason McLaughlin This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "proto.h" /* compile a regular expression, or return NULL on failure */ regex_t *reg_compile(char *pattern, int flags) { int rerr; regex_t *re; re = xmalloc(sizeof(regex_t)); rerr = regcomp2(re, pattern, flags); if (rerr != 0) { putlog(MMLOG_ERROR, "failed to compile regular expression: %s", pattern); xfree(re); re = NULL; } return re; } /* free a regular expression and the pointer it's stored in */ void reg_free(regex_t * re) { ASSERT(re != NULL); regfree2(re); xfree(re); } /* perform a regular expression match, return 0 on success */ int reg_exec(regex_t * re, char *string) { int rerr; rerr = regexec2(re, string, 0, NULL, 0); return rerr; } regex_sub_t *reg_sub_compile(char *pattern, int flags) { int erroff; const char *err; regex_sub_t *ret; ret = xmalloc(sizeof(regex_sub_t)); ret->pattern = pcre_compile(pattern, flags, &err, &erroff, NULL); if (ret->pattern == NULL) { putlog(MMLOG_ERROR, "failed to compile regular expression: %s", pattern); xfree(ret); return NULL; } ret->extra = pcre_study(ret->pattern, 0, &err); return ret; } /* free a regex_sub_t structure */ void reg_sub_free(regex_sub_t * re) { if (re->pattern != NULL) xfree(re->pattern); if (re->extra != NULL) xfree(re->extra); xfree(re); } /* perform a regular expression match and store matching substrings */ regmatch_sub_t *reg_sub_exec(regex_sub_t * pe, char *string) { int subcount, vectors[PCRE_MAX_SUBSTRING * 3]; regmatch_sub_t *ret; subcount = pcre_exec(pe->pattern, pe->extra, string, strlen(string), 0, 0, vectors, PCRE_MAX_SUBSTRING * 3); if (subcount > 0) { ret = xmalloc(sizeof(regmatch_sub_t)); ret->rm_so = vectors[0]; ret->rm_eo = vectors[1]; ret->subcount = subcount; pcre_get_substring_list(string, vectors, subcount, &ret->substrings); return ret; } else return NULL; } /* free regmatch_sub_t structure and all substrings inside */ void reg_sub_match_free(regmatch_sub_t * rm) { pcre_free_substring_list(rm->substrings); xfree(rm); } /* replace all backreferences in a string with the actual matching string */ char *reg_sub_parse(regmatch_sub_t * rst, char *string) { int x; char *ptr = string, *ret = NULL; FILEBUF *filebuf; filebuf = filebuf_new(); while (*ptr) { if (*ptr == '$') { if (!ptr[1] || ptr[1] == '$') { filebuf_add(filebuf, "$", 1); ptr += (ptr[1]) ? 2 : 1; } else { x = ptr[1] - '0'; if (x >= 0 && x < rst->subcount) filebuf_add(filebuf, rst->substrings[x], strlen(rst->substrings[x])); ptr += 2; } } else if (*ptr == '\\') { /* handle escape sequences */ switch (ptr[1]) { case '\\': filebuf_add(filebuf, "\\", 1); break; case 'n': filebuf_add(filebuf, "\n", 1); break; case 'r': filebuf_add(filebuf, "\r", 1); break; case 't': filebuf_add(filebuf, "\t", 1); break; case 'f': filebuf_add(filebuf, "\f", 1); break; case 'a': filebuf_add(filebuf, "\a", 1); break; case 'e': filebuf_add(filebuf, "\e", 1); break; default: filebuf_add(filebuf, &ptr[1], 1); break; } ptr += (ptr[1]) ? 2 : 1; } else { filebuf_add(filebuf, ptr, 1); ptr++; } } filebuf_add(filebuf, "", 1); filebuf_shorten(filebuf); ret = filebuf->data; filebuf->data = NULL; filebuf_free(filebuf); return ret; } /* replace all instances of text matching a regexp pattern with another string */ void reg_replace(FILEBUF * filebuf, regex_sub_t * pe, char *replace) { char *r; int len, e = 0; regmatch_sub_t *rmatch; FILEBUF *new = NULL; filebuf_add(filebuf, "", 1); while ((rmatch = reg_sub_exec(pe, &filebuf->data[e]))) { if (new == NULL) new = filebuf_new(); filebuf_add(new, &filebuf->data[e], rmatch->rm_so); rmatch->rm_so += e; rmatch->rm_eo += e; len = rmatch->rm_eo - rmatch->rm_so; e = rmatch->rm_eo; if (replace != NULL) { r = reg_sub_parse(rmatch, replace); filebuf_add(new, r, strlen(r)); xfree(r); } reg_sub_match_free(rmatch); } if (new != NULL) { filebuf_add(new, &filebuf->data[e], filebuf->size - e - 1); xfree(filebuf->data); filebuf->data = new->data; filebuf->size = new->size; new->data = NULL; filebuf_free(new); } else filebuf_resize(filebuf, filebuf->size - 1); } /* replace all instances of a plaintext string with another */ void string_replace(FILEBUF * filebuf, char *string, char *replace) { char *ptr; int len, len2 = 0, e = 0; filebuf_add(filebuf, "", 1); len = strlen(string); if (replace != NULL) len2 = strlen(replace); while ((ptr = strstr(&filebuf->data[e], string))) { e = (ptr - filebuf->data) + len; if (replace == NULL) { memcpy(ptr, ptr + len, ptr - filebuf->data - len); filebuf_resize(filebuf, filebuf->size - len); e -= len; } else { filebuf_replace(filebuf, ptr - filebuf->data, ptr - filebuf->data + len, replace); e += (len2 - len); } } filebuf_resize(filebuf, filebuf->size - 1); }