blob: 64f93c30ecdf7b11382dc92d9462e94507383da2 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Regex and string management functions.
3 *
Willy Tarreauf4f04122010-01-28 18:10:50 +01004 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <stdlib.h>
15#include <string.h>
16
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020017#include <common/config.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020018#include <common/regex.h>
19#include <common/standard.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020020#include <proto/log.h>
21
22/* regex trash buffer used by various regex tests */
23regmatch_t pmatch[MAX_MATCH]; /* rm_so, rm_eo for regular expressions */
24
25
Willy Tarreaub17916e2006-10-15 15:17:57 +020026int exp_replace(char *dst, char *src, const char *str, const regmatch_t *matches)
Willy Tarreaubaaee002006-06-26 02:48:02 +020027{
28 char *old_dst = dst;
29
30 while (*str) {
31 if (*str == '\\') {
32 str++;
Willy Tarreau8f8e6452007-06-17 21:51:38 +020033 if (isdigit((unsigned char)*str)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +020034 int len, num;
35
36 num = *str - '0';
37 str++;
38
39 if (matches[num].rm_eo > -1 && matches[num].rm_so > -1) {
40 len = matches[num].rm_eo - matches[num].rm_so;
41 memcpy(dst, src + matches[num].rm_so, len);
42 dst += len;
43 }
44
45 } else if (*str == 'x') {
46 unsigned char hex1, hex2;
47 str++;
48
49 hex1 = toupper(*str++) - '0';
50 hex2 = toupper(*str++) - '0';
51
52 if (hex1 > 9) hex1 -= 'A' - '9' - 1;
53 if (hex2 > 9) hex2 -= 'A' - '9' - 1;
54 *dst++ = (hex1<<4) + hex2;
55 } else {
56 *dst++ = *str++;
57 }
58 } else {
59 *dst++ = *str++;
60 }
61 }
62 *dst = '\0';
63 return dst - old_dst;
64}
65
66/* returns NULL if the replacement string <str> is valid, or the pointer to the first error */
Willy Tarreaub17916e2006-10-15 15:17:57 +020067const char *check_replace_string(const char *str)
Willy Tarreaubaaee002006-06-26 02:48:02 +020068{
Willy Tarreaub17916e2006-10-15 15:17:57 +020069 const char *err = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +020070 while (*str) {
71 if (*str == '\\') {
72 err = str; /* in case of a backslash, we return the pointer to it */
73 str++;
74 if (!*str)
75 return err;
Willy Tarreau8f8e6452007-06-17 21:51:38 +020076 else if (isdigit((unsigned char)*str))
Willy Tarreaubaaee002006-06-26 02:48:02 +020077 err = NULL;
78 else if (*str == 'x') {
79 str++;
80 if (!ishex(*str))
81 return err;
82 str++;
83 if (!ishex(*str))
84 return err;
85 err = NULL;
86 }
87 else {
88 Warning("'\\%c' : deprecated use of a backslash before something not '\\','x' or a digit.\n", *str);
89 err = NULL;
90 }
91 }
92 str++;
93 }
94 return err;
95}
96
97
98/* returns the pointer to an error in the replacement string, or NULL if OK */
Willy Tarreaub17916e2006-10-15 15:17:57 +020099const char *chain_regex(struct hdr_exp **head, const regex_t *preg,
Willy Tarreauf4f04122010-01-28 18:10:50 +0100100 int action, const char *replace, void *cond)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200101{
102 struct hdr_exp *exp;
103
104 if (replace != NULL) {
Willy Tarreaub17916e2006-10-15 15:17:57 +0200105 const char *err;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200106 err = check_replace_string(replace);
107 if (err)
108 return err;
109 }
110
111 while (*head != NULL)
112 head = &(*head)->next;
113
114 exp = calloc(1, sizeof(struct hdr_exp));
115
116 exp->preg = preg;
117 exp->replace = replace;
118 exp->action = action;
Willy Tarreauf4f04122010-01-28 18:10:50 +0100119 exp->cond = cond;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200120 *head = exp;
121
122 return NULL;
123}
124
Thierry FOURNIER799c0422013-12-06 20:36:20 +0100125int regex_comp(const char *str, struct my_regex *regex, int cs, int cap, char **err)
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200126{
Thierry FOURNIER39e258f2013-12-06 20:38:46 +0100127 /* copy the original regex format */
128 regex->regstr = strdup(str);
129 if (!regex->regstr) {
130 memprintf(err, "out of memory");
131 return 0;
132 }
133
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200134#ifdef USE_PCRE_JIT
135 int flags = 0;
136 const char *error;
137 int erroffset;
138
139 if (!cs)
140 flags |= PCRE_CASELESS;
141 if (!cap)
142 flags |= PCRE_NO_AUTO_CAPTURE;
143
144 regex->reg = pcre_compile(str, flags, &error, &erroffset, NULL);
145 if (!regex->reg) {
Thierry FOURNIER39e258f2013-12-06 20:38:46 +0100146 free(regex->regstr);
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200147 memprintf(err, "regex '%s' is invalid (error=%s, erroffset=%d)", str, error, erroffset);
148 return 0;
149 }
150
151 regex->extra = pcre_study(regex->reg, PCRE_STUDY_JIT_COMPILE, &error);
152 if (!regex->extra) {
Thierry FOURNIER39e258f2013-12-06 20:38:46 +0100153 free(regex->regstr);
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200154 pcre_free(regex->reg);
155 memprintf(err, "failed to compile regex '%s' (error=%s)", str, error);
156 return 0;
157 }
158#else
159 int flags = REG_EXTENDED;
160
161 if (!cs)
162 flags |= REG_ICASE;
163 if (!cap)
164 flags |= REG_NOSUB;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200165
Thierry FOURNIER799c0422013-12-06 20:36:20 +0100166 if (regcomp(&regex->regex, str, flags) != 0) {
Thierry FOURNIER39e258f2013-12-06 20:38:46 +0100167 free(regex->regstr);
Thierry FOURNIERed5a4ae2013-10-14 14:07:36 +0200168 memprintf(err, "regex '%s' is invalid", str);
169 return 0;
170 }
171#endif
172 return 1;
173}
Willy Tarreaubaaee002006-06-26 02:48:02 +0200174
175/*
176 * Local variables:
177 * c-indent-level: 8
178 * c-basic-offset: 8
179 * End:
180 */