]> granicus.if.org Git - apache/blob - server/util_expr_scan.l
Add compiled and loaded PCRE version numbers
[apache] / server / util_expr_scan.l
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 /*
18  *  ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
19  */
20
21 /*  _________________________________________________________________
22 **
23 **  Expression Scanner
24 **  _________________________________________________________________
25 */
26
27 %pointer
28 %option batch
29 %option never-interactive
30 %option nodefault
31 %option noyywrap
32 %option reentrant
33 %option bison-bridge
34 %option warn
35 %option noinput nounput noyy_top_state
36 %option stack
37 %x str
38 %x var
39 %x vararg
40 %x regex regex_flags
41
42 %{
43 #include "util_expr_private.h"
44 #include "util_expr_parse.h"
45 #include "http_main.h"
46 #include "http_log.h"
47
48 #undef  YY_INPUT
49 #define YY_INPUT(buf,result,max_size)                       \
50 {                                                           \
51     if ((result = MIN(max_size, yyextra->inputbuf           \
52                               + yyextra->inputlen           \
53                               - yyextra->inputptr)) <= 0)   \
54     {                                                       \
55         result = YY_NULL;                                   \
56     }                                                       \
57     else {                                                  \
58         memcpy(buf, yyextra->inputptr, result);             \
59         yyextra->inputptr += result;                        \
60     }                                                       \
61 }
62
63 /*
64  * XXX: It would be nice if we could recover somehow, e.g. via
65  * XXX: longjmp. It is not clear if the scanner is in any state
66  * XXX: to be cleaned up, though.
67  */
68 #define YY_FATAL_ERROR(msg)                                     \
69     do {                                                        \
70         ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, \
71                       "expr parser fatal error (BUG?): "        \
72                       "%s, exiting", msg);                      \
73          abort();                                               \
74     } while (0)
75
76 #define YY_EXTRA_TYPE ap_expr_parse_ctx_t*
77
78 #define PERROR(msg) do { yyextra->error2 = msg ; return T_ERROR; } while (0)
79
80 #define str_ptr     (yyextra->scan_ptr)
81 #define str_buf     (yyextra->scan_buf)
82 #define str_del     (yyextra->scan_del)
83
84 #define STR_APPEND(c) do {                          \
85         *str_ptr++ = (c);                           \
86         if (str_ptr >= str_buf + sizeof(str_buf))   \
87             PERROR("String too long");              \
88     } while (0)
89
90 %}
91
92
93 %%
94
95   char  regex_buf[MAX_STRING_LEN];
96   char *regex_ptr = NULL;
97   char  regex_del = '\0';
98
99 %{
100  /*
101   * Set initial state for string expressions
102   */
103   if (yyextra->at_start) {
104     yyextra->at_start = 0;
105     if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) {
106         BEGIN(str);
107         return T_EXPR_STRING;
108     }
109     else {
110         return T_EXPR_BOOL;
111     }
112   }
113 %}
114
115  /*
116   * Whitespaces
117   */
118 [ \t\n]+ { 
119     /* NOP */
120 }
121
122  /*
123   * strings ("..." and '...')
124   */
125 ["'] {
126     str_ptr = str_buf;
127     str_del = yytext[0];
128     BEGIN(str);
129     return T_STR_BEGIN;
130 }
131 <str>["'] {
132     if (yytext[0] == str_del) {
133         if (YY_START == var) {
134             PERROR("Unterminated variable in string");
135         }
136         else if (str_ptr == str_buf) {
137             BEGIN(INITIAL);
138             return T_STR_END;
139         }
140         else {
141             /* return what we have so far and scan delimiter again */
142             *str_ptr = '\0';
143             yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
144             yyless(0);
145             str_ptr = str_buf;
146             return T_STRING;
147         }
148     }
149     else {
150         STR_APPEND(yytext[0]);
151     }
152 }
153 <str,var,vararg>\n {
154     PERROR("Unterminated string or variable");
155 }
156 <var,vararg><<EOF>> {
157     PERROR("Unterminated string or variable");
158 }
159 <str><<EOF>> {
160     if (!(yyextra->flags & AP_EXPR_FLAG_STRING_RESULT)) {
161         PERROR("Unterminated string or variable");
162     }
163     else {
164         *str_ptr = '\0';
165         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
166         str_ptr = str_buf;
167         BEGIN(INITIAL);
168         return T_STRING;
169     }
170 }
171
172 <str,vararg>\\[0-7]{1,3} {
173     int result;
174
175     (void)sscanf(yytext+1, "%o", &result);
176     if (result > 0xff) {
177         PERROR("Escape sequence out of bound");
178     }
179     else {
180         STR_APPEND(result);
181     }
182 }
183 <str,vararg>\\[0-9]+ {
184     PERROR("Bad escape sequence");
185 }
186 <str,vararg>\\n      { STR_APPEND('\n'); }
187 <str,vararg>\\r      { STR_APPEND('\r'); }
188 <str,vararg>\\t      { STR_APPEND('\t'); }
189 <str,vararg>\\b      { STR_APPEND('\b'); }
190 <str,vararg>\\f      { STR_APPEND('\f'); }
191 <str,vararg>\\(.|\n) { STR_APPEND(yytext[1]); }
192
193  /* regexp backref inside string/arg */
194 <str,vararg>[$][0-9] {
195     if (str_ptr != str_buf) {
196         /* return what we have so far and scan '$x' again */
197         *str_ptr = '\0';
198         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
199         str_ptr = str_buf;
200         yyless(0);
201         return T_STRING;
202     }
203     else {
204         yylval->num = yytext[1] - '0';
205         return T_REGEX_BACKREF;
206     }
207 }
208
209 <str,vararg>[^\\\n"'%}$]+ {
210     char *cp = yytext;
211     while (*cp != '\0') {
212         STR_APPEND(*cp);
213         cp++;
214     }
215 }
216
217  /* variable inside string/arg */
218 <str,vararg>%\{ {
219     if (str_ptr != str_buf) {
220         /* return what we have so far and scan '%{' again */
221         *str_ptr = '\0';
222         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
223         yyless(0);
224         str_ptr = str_buf;
225         return T_STRING;
226     }
227     else {
228         yy_push_state(var, yyscanner);
229         return T_VAR_BEGIN;
230     }
231 }
232
233 <vararg>[%$] {
234      STR_APPEND(yytext[0]);
235 }
236
237 <str>[%}$] {
238      STR_APPEND(yytext[0]);
239 }
240
241 %\{ {
242     yy_push_state(var, yyscanner);
243     return T_VAR_BEGIN;
244 }
245
246 [$][0-9] {
247     yylval->num = yytext[1] - '0';
248     return T_REGEX_BACKREF;
249 }
250
251  /*
252   * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax
253   */
254 <var>[a-ij-rs-zA-IJ-RS-Z][a-ij-rs-zA-IJ-RS-Z0-9_]* {
255     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
256     return T_ID;
257 }
258
259 <var>\} {
260     yy_pop_state(yyscanner);
261     return T_VAR_END;
262 }
263
264 <var>: {
265     BEGIN(vararg);
266     return yytext[0];
267 }
268
269 <var>.|\n {
270     char *msg = apr_psprintf(yyextra->pool,
271                              "Invalid character in variable name '%c'", yytext[0]);
272     PERROR(msg);
273 }
274
275 <vararg>\} {
276     if (str_ptr != str_buf) {
277         /* return what we have so far and scan '}' again */
278         *str_ptr = '\0';
279         yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf);
280         str_ptr = str_buf;
281         yyless(0);
282         return T_STRING;
283     }
284     else {
285         yy_pop_state(yyscanner);
286         return T_VAR_END;
287     }
288 }
289
290  /*
291   * Regular Expression
292   */
293 "m"[/#$%^,;:_\?\|\^\-\!\.\'\"] {
294     regex_del = yytext[1];
295     regex_ptr = regex_buf;
296     BEGIN(regex);
297 }
298 "/" {
299     regex_del = yytext[0];
300     regex_ptr = regex_buf;
301     BEGIN(regex);
302 }
303 <regex>.|\n {
304     if (yytext[0] == regex_del) {
305         *regex_ptr = '\0';
306         BEGIN(regex_flags);
307     }
308     else {
309         *regex_ptr++ = yytext[0];
310         if (regex_ptr >= regex_buf + sizeof(regex_buf))
311             PERROR("Regexp too long");
312     }
313 }
314 <regex_flags>i {
315     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
316     BEGIN(INITIAL);
317     return T_REGEX_I;
318 }
319 <regex_flags>.|\n {
320     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
321     yyless(0);
322     BEGIN(INITIAL);
323     return T_REGEX;
324 }
325 <regex_flags><<EOF>> {
326     yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
327     BEGIN(INITIAL);
328     return T_REGEX;
329 }
330
331  /*
332   * Operators
333   */
334 ==?   { return T_OP_STR_EQ; }
335 "!="  { return T_OP_STR_NE; }
336 "<"   { return T_OP_STR_LT; }
337 "<="  { return T_OP_STR_LE; }
338 ">"   { return T_OP_STR_GT; }
339 ">="  { return T_OP_STR_GE; }
340 "=~"  { return T_OP_REG; }
341 "!~"  { return T_OP_NRE; }
342 "and" { return T_OP_AND; }
343 "&&"  { return T_OP_AND; }
344 "or"  { return T_OP_OR; }
345 "||"  { return T_OP_OR; }
346 "not" { return T_OP_NOT; }
347 "!"   { return T_OP_NOT; }
348 "."   { return T_OP_CONCAT; }
349 "-in"  { return T_OP_IN; }
350 "-eq"  { return T_OP_EQ; }
351 "-ne"  { return T_OP_NE; }
352 "-ge"  { return T_OP_GE; }
353 "-le"  { return T_OP_LE; }
354 "-gt"  { return T_OP_GT; }
355 "-lt"  { return T_OP_LT; }
356
357  /* for compatibility with ssl_expr */
358 "lt"  { return T_OP_LT; }
359 "le"  { return T_OP_LE; }
360 "gt"  { return T_OP_GT; }
361 "ge"  { return T_OP_GE; }
362 "ne"  { return T_OP_NE; }
363 "eq"  { return T_OP_EQ; }
364 "in"  { return T_OP_IN; }
365
366 "-"[a-ij-rs-zA-IJ-RS-Z_] {
367     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
368     return T_OP_UNARY;
369 }
370
371 "-"[a-ij-rs-zA-IJ-RS-Z_][a-ij-rs-zA-IJ-RS-Z_0-9]+ {
372     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
373     return T_OP_BINARY;
374 }
375
376  /*
377   * Specials
378   */
379 "true"  { return T_TRUE; }
380 "false" { return T_FALSE; }
381
382  /*
383   * Digits
384   */
385 -?[0-9]+ {
386     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
387     return T_DIGIT;
388 }
389
390  /*
391   * Identifiers
392   */
393 [a-ij-rs-zA-IJ-RS-Z][a-ij-rs-zA-IJ-RS-Z0-9_]* {
394     yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
395     return T_ID;
396 }
397
398  /*
399   * These are parts of the grammar and are returned as is
400   */
401 [(){},:] {
402     return yytext[0];
403 }
404
405  /*
406   * Anything else is an error
407   */
408 .|\n {
409     char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]);
410     PERROR(msg);
411 }
412
413 %%
414
415