]> granicus.if.org Git - apache/blob - server/util_regex.c
Remove cruft that accidentally got into r999533
[apache] / server / util_regex.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr.h"
18 #include "apr_lib.h"
19 #include "apr_pools.h"
20 #include "apr_strings.h"
21 #include "ap_config.h"
22 #include "ap_regex.h"
23 #include "httpd.h"
24
25 AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool,
26                                            const char *pattern)
27 {
28     /* perl style patterns
29      * add support for more as and when wanted
30      * substitute: s/rx/subs/
31      * match: m/rx/ or just /rx/
32      */
33
34     /* allow any nonalnum delimiter as first or second char.
35      * If we ever use this with non-string pattern we'll need an extra check
36      */
37     const char *endp = 0;
38     const char *str = pattern;
39     const char *rxstr;
40     ap_rxplus_t *ret = apr_pcalloc(pool, sizeof(ap_rxplus_t));
41     char delim = 0;
42     enum { SUBSTITUTE = 's', MATCH = 'm'} action = MATCH;
43     if (!apr_isalnum(pattern[0])) {
44         delim = *str++;
45     }
46     else if (pattern[0] == 's' && !apr_isalnum(pattern[1])) {
47         action = SUBSTITUTE;
48         delim = pattern[1];
49         str += 2;
50     }
51     else if (pattern[0] == 'm' && !apr_isalnum(pattern[1])) {
52         delim = pattern[1];
53         str += 2;
54     }
55     /* TODO: support perl's after/before */
56     /* FIXME: fix these simplminded delims */
57
58     /* we think there's a delimiter.  Allow for it not to be if unmatched */
59     if (delim) {
60         endp = ap_strchr_c(str, delim);
61     }
62     if (!endp) { /* there's no delim  or flags */
63         if (ap_regcomp(&ret->rx, pattern, 0) == 0) {
64             apr_pool_cleanup_register(pool, &ret->rx, (void*) ap_regfree,
65                                       apr_pool_cleanup_null);
66             return ret;
67         }
68         else {
69             return NULL;
70         }
71     }
72
73     /* We have a delimiter.  Use it to extract the regexp */
74     rxstr = apr_pstrndup(pool, str, endp-str);
75
76     /* If it's a substitution, we need the replacement string
77      * TODO: possible future enhancement - support other parsing
78      * in the replacement string.
79      */
80     if (action == SUBSTITUTE) {
81         str = endp+1;
82         if (!*str || (endp = ap_strchr_c(str, delim), !endp)) {
83             /* missing replacement string is an error */
84             return NULL;
85         }
86         ret->subs = apr_pstrndup(pool, str, (endp-str));
87     }
88
89     /* anything after the current delimiter is flags */
90     while (*++endp) {
91         switch (*endp) {
92         case 'i': ret->flags |= AP_REG_ICASE; break;
93         case 'm': ret->flags |= AP_REG_NEWLINE; break;
94         case 'n': ret->flags |= AP_REG_NOMEM; break;
95         case 'g': ret->flags |= AP_REG_MULTI; break;
96         case 's': ret->flags |= AP_REG_DOTALL; break;
97         case '^': ret->flags |= AP_REG_NOTBOL; break;
98         case '$': ret->flags |= AP_REG_NOTEOL; break;
99         default: break; /* we should probably be stricter here */
100         }
101     }
102     if (ap_regcomp(&ret->rx, rxstr, ret->flags) == 0) {
103         apr_pool_cleanup_register(pool, &ret->rx, (void*) ap_regfree,
104                                   apr_pool_cleanup_null);
105     }
106     else {
107         return NULL;
108     }
109     if (!(ret->flags & AP_REG_NOMEM)) {
110         /* count size of memory required, starting at 1 for the whole-match
111          * Simpleminded should be fine 'cos regcomp already checked syntax
112          */
113         ret->nmatch = 1;
114         while (*rxstr) {
115             switch (*rxstr++) {
116             case '\\':  /* next char is escaped - skip it */
117                 if (*rxstr != 0) {
118                     ++rxstr;
119                 }
120                 break;
121             case '(':   /* unescaped bracket implies memory */
122                 ++ret->nmatch;
123                 break;
124             default:
125                 break;
126             }
127         }
128         ret->pmatch = apr_palloc(pool, ret->nmatch*sizeof(ap_regmatch_t));
129     }
130     return ret;
131 }
132
133 AP_DECLARE(int) ap_rxplus_exec(apr_pool_t *pool, ap_rxplus_t *rx,
134                                const char *pattern, char **newpattern)
135                                //int max_iterations)
136 {
137     int ret = 1;
138     int startl, oldl, newl, diffsz;
139     const char *remainder;
140     char *subs;
141 /* snrf process_regexp from mod_headers */
142     if (ap_regexec(&rx->rx, pattern, rx->nmatch, rx->pmatch, rx->flags) != 0) {
143         rx->match = NULL;
144         return 0; /* no match, nothing to do */
145     }
146     rx->match = pattern;
147     if (rx->subs) {
148         *newpattern = ap_pregsub(pool, rx->subs, pattern,
149                                  rx->nmatch, rx->pmatch);
150         if (!*newpattern) {
151             return 0; /* FIXME - should we do more to handle error? */
152         }
153         startl = rx->pmatch[0].rm_so;
154         oldl = rx->pmatch[0].rm_eo - startl;
155         newl = strlen(*newpattern);
156         diffsz = newl - oldl;
157         remainder = pattern + startl + oldl;
158         if (rx->flags & AP_REG_MULTI) {
159             /* recurse to do any further matches */
160             char *subs;
161             ret += ap_rxplus_exec(pool, rx, remainder, &subs);
162             if (ret > 1) {
163                 /* a further substitution happened */
164                 diffsz += strlen(subs) - strlen(remainder);
165                 remainder = subs;
166             }
167         }
168         subs  = apr_palloc(pool, strlen(pattern) + 1 + diffsz);
169         memcpy(subs, pattern, startl);
170         memcpy(subs+startl, *newpattern, newl);
171         strcpy(subs+startl+newl, remainder);
172         *newpattern = subs;
173     }
174     return ret;
175 }
176 #ifdef DOXYGEN
177 AP_DECLARE(int) ap_rxplus_nmatch(ap_rxplus_t *rx)
178 {
179     return (rx->match != NULL) ? rx->nmatch : 0;
180 }
181 #endif
182
183 /* If this blows up on you, see the notes in the header/apidoc
184  * rx->match is a pointer and it's your responsibility to ensure
185  * it hasn't gone out-of-scope since the last ap_rxplus_exec
186  */
187 AP_DECLARE(void) ap_rxplus_match(ap_rxplus_t *rx, int n, int *len,
188                                  const char **match)
189 {
190     if (n >= 0 && n < ap_rxplus_nmatch(rx)) {
191         *match = rx->match + rx->pmatch[n].rm_so;
192         *len = rx->pmatch[n].rm_eo - rx->pmatch[n].rm_so;
193     }
194     else {
195         *len = -1;
196         *match = NULL;
197     }
198 }
199 AP_DECLARE(char*) ap_rxplus_pmatch(apr_pool_t *pool, ap_rxplus_t *rx, int n)
200 {
201     int len;
202     const char *match;
203     ap_rxplus_match(rx, n, &len, &match);
204     return (match != NULL) ? apr_pstrndup(pool, match, len) : NULL;
205 }