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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl
21 /* _________________________________________________________________
24 ** _________________________________________________________________
29 %option never-interactive
35 %option noinput nounput noyy_top_state
40 %x regex regsub regflags
43 #include "util_expr_private.h"
44 #include "util_expr_parse.h"
45 #include "http_main.h"
50 #define YY_INPUT(buf,result,max_size) \
52 if ((result = MIN(max_size, yyextra->inputbuf \
54 - yyextra->inputptr)) <= 0) \
59 memcpy(buf, yyextra->inputptr, result); \
60 yyextra->inputptr += result; \
65 * XXX: It would be nice if we could recover somehow, e.g. via
66 * XXX: longjmp. It is not clear if the scanner is in any state
67 * XXX: to be cleaned up, though.
69 static int unreachable = 0;
70 #define YY_FATAL_ERROR(msg) \
72 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, \
74 "expr parser fatal error (BUG?): " \
75 "%s, exiting", msg); \
77 /* Not reached, silence [-Wunused-function] */ \
78 yy_fatal_error(msg, yyscanner); \
85 #define YY_EXTRA_TYPE ap_expr_parse_ctx_t*
87 #define PERROR(msg) do { \
88 yyextra->error2 = msg; \
92 #define PERROR_CHAR(prefix, chr) do { \
94 if (apr_isprint((chr))) { \
95 msg = apr_psprintf(yyextra->pool, prefix "'%c'", (char)(chr)); \
98 msg = apr_psprintf(yyextra->pool, prefix "'\\x%.2X'", (int)(chr)); \
103 #define STACK_PUSH() do { \
104 ap_expr_parser_stack_t *sk; \
105 if (yyextra->spares) { \
106 sk = yyextra->spares; \
107 yyextra->spares = sk->next; \
110 sk = apr_palloc(yyextra->ptemp, sizeof(*sk)); \
112 sk->scan_ptr = sk->scan_buf; \
113 sk->scan_stop = sk->scan_buf[0] = '\0'; \
115 sk->next = yyextra->current; \
116 yyextra->current = sk; \
119 #define STACK_POP() do { \
120 ap_expr_parser_stack_t *sk; \
121 sk = yyextra->current; \
122 yyextra->current = sk->next; \
123 sk->next = yyextra->spares; \
124 yyextra->spares = sk; \
127 #define STATE_PUSH(st, sk) do { \
128 yy_push_state((st), yyscanner); \
134 #define STATE_POP(sk) do { \
138 yy_pop_state(yyscanner); \
141 #define str_ptr (yyextra->current->scan_ptr)
142 #define str_buf (yyextra->current->scan_buf)
143 #define str_stop (yyextra->current->scan_stop)
144 #define str_flag (yyextra->current->scan_flag)
146 #define STR_APPEND_CHECK(chr, chk) do { \
147 if ((chk) && apr_iscntrl((chr))) { \
148 PERROR_CHAR("Invalid string character ", (chr)); \
150 if (str_ptr >= str_buf + sizeof(str_buf) - 1) { \
151 PERROR("String too long"); \
153 *str_ptr++ = (char)(chr); \
156 #define STR_APPEND_NOCHECK(chr) \
157 STR_APPEND_CHECK((chr), 0)
159 #define STR_EMPTY() \
162 #define STR_RETURN() \
163 (apr_pstrdup(yyextra->pool, (*str_ptr = '\0', str_ptr = str_buf)))
170 TOKEN ([a-zA-Z][a-zA-Z0-9_]*)
174 VAREXP_BEGIN (\%\{\:)
176 REG_SEP [/#$%^|?!'",;:._-]
183 * Set initial state for string expressions
185 if (yyextra->at_start) {
186 yyextra->at_start = 0;
187 if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) {
189 return T_EXPR_STRING;
199 * Back off INITIAL pushes
202 STATE_POP(0); /* <str> */
203 if (YY_START != INITIAL) {
204 PERROR("Unterminated string");
206 yylval->cpVal = STR_RETURN();
207 STACK_POP(); /* ^ after this */
211 STATE_POP(1); /* <expr> */
212 if (YY_START != INITIAL) {
213 PERROR("Unterminated expression");
218 if (yytext[0] == str_stop) {
220 yyless(0); /* come back below */
221 yylval->cpVal = STR_RETURN();
224 STATE_POP(1); /* <str> */
227 STR_APPEND_NOCHECK(yytext[0]);
230 /* regexp backref inside string/arg */
231 <str,vararg,regsub>{BACKREF} {
233 yyless(0); /* come back below */
234 yylval->cpVal = STR_RETURN();
237 yylval->num = yytext[1] - '0';
241 /* variable inside string/arg */
242 <str,vararg,regsub>{VAR_BEGIN} {
244 yyless(0); /* come back below */
245 yylval->cpVal = STR_RETURN();
252 <str,vararg,regsub>{VAREXP_BEGIN} {
254 yyless(0); /* come back below */
255 yylval->cpVal = STR_RETURN();
259 return T_VAREXP_BEGIN;
262 /* Any non-octal or octal higher than 377 (decimal 255) is invalid */
263 <str,vararg,regsub>\\([4-9][0-9]{2}|[8-9][0-9]{0,2}) {
264 PERROR("Bad character escape sequence");
266 <str,vararg,regsub>\\[0-7]{1,3} {
268 (void)sscanf(yytext+1, "%o", &result);
269 STR_APPEND_NOCHECK(result);
271 <str,vararg,regsub>\\x[0-9A-Fa-f]{1,2} {
273 (void)sscanf(yytext+1, "%x", &result);
274 STR_APPEND_NOCHECK(result);
276 <str,vararg,regsub>\\n { STR_APPEND_NOCHECK('\n'); }
277 <str,vararg,regsub>\\r { STR_APPEND_NOCHECK('\r'); }
278 <str,vararg,regsub>\\t { STR_APPEND_NOCHECK('\t'); }
279 <str,vararg,regsub>\\b { STR_APPEND_NOCHECK('\b'); }
280 <str,vararg,regsub>\\f { STR_APPEND_NOCHECK('\f'); }
281 <str,vararg,regsub>\\. { STR_APPEND_CHECK(yytext[1], 1); }
283 <str,vararg,regsub>\n {
284 PERROR("Unterminated string or variable");
288 STR_APPEND_CHECK(yytext[0], 1);
297 str_stop = yytext[0];
301 <expr>{VAREXP_BEGIN} {
303 return T_VAREXP_BEGIN;
306 STATE_POP(1); /* <expr> */
316 yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
320 STATE_PUSH(vararg, 0);
324 yyless(0); /* let <var> handle */
325 yylval->cpVal = STR_RETURN();
326 STATE_POP(0); /* <vararg> */
330 STR_APPEND_CHECK(yytext[0], 1);
333 STATE_POP(1); /* <var> */
337 PERROR_CHAR("Unexpected variable character ", yytext[0]);
339 <var,vararg><<EOF>> {
340 PERROR("Unterminated variable");
348 STATE_PUSH(regex, 1);
349 str_stop = yytext[0];
353 <expr>[ms]{REG_SEP} {
354 STATE_PUSH(regex, 1);
355 str_stop = yytext[1];
356 str_flag = yytext[0];
357 return (str_flag == 'm') ? T_REGEX : T_REGSUB;
360 if (yytext[0] == str_stop) {
361 yylval->cpVal = STR_RETURN();
362 STATE_POP(0); /* <regex> */
363 if (str_flag == 'm') {
364 STATE_PUSH(regflags, 0);
367 STATE_PUSH(regsub, 0);
371 STR_APPEND_CHECK(yytext[0], 1);
374 if (yytext[0] == str_stop) {
375 yylval->cpVal = STR_RETURN();
376 STATE_POP(0); /* <regsub> */
377 STATE_PUSH(regflags, 0);
380 STR_APPEND_CHECK(yytext[0], 1);
383 if (!ap_strchr_c("ismg", yytext[0])) {
384 if (apr_isalnum(yytext[0])) {
385 PERROR("Invalid regexp flag(s)");
387 yyless(0); /* not a flags, rewind */
388 yylval->cpVal = STR_RETURN();
389 STATE_POP(1); /* <regflags> */
392 STR_APPEND_NOCHECK(yytext[0]);
395 yylval->cpVal = STR_RETURN();
396 STATE_POP(1); /* <regflags> */
399 <regex,regsub><<EOF>> {
400 PERROR("Unterminated regexp");
404 yylval->num = yytext[1] - '0';
411 <expr>==? { return T_OP_STR_EQ; }
412 <expr>"!=" { return T_OP_STR_NE; }
413 <expr>"<" { return T_OP_STR_LT; }
414 <expr>"<=" { return T_OP_STR_LE; }
415 <expr>">" { return T_OP_STR_GT; }
416 <expr>">=" { return T_OP_STR_GE; }
417 <expr>"=~" { return T_OP_REG; }
418 <expr>"!~" { return T_OP_NRE; }
419 <expr>"and" { return T_OP_AND; }
420 <expr>"&&" { return T_OP_AND; }
421 <expr>"or" { return T_OP_OR; }
422 <expr>"||" { return T_OP_OR; }
423 <expr>"not" { return T_OP_NOT; }
424 <expr>"!" { return T_OP_NOT; }
425 <expr>"." { return T_OP_CONCAT; }
426 <expr>"-in" { return T_OP_IN; }
427 <expr>"-eq" { return T_OP_EQ; }
428 <expr>"-ne" { return T_OP_NE; }
429 <expr>"-ge" { return T_OP_GE; }
430 <expr>"-le" { return T_OP_LE; }
431 <expr>"-gt" { return T_OP_GT; }
432 <expr>"-lt" { return T_OP_LT; }
434 /* for compatibility with ssl_expr */
435 <expr>"lt" { return T_OP_LT; }
436 <expr>"le" { return T_OP_LE; }
437 <expr>"gt" { return T_OP_GT; }
438 <expr>"ge" { return T_OP_GE; }
439 <expr>"ne" { return T_OP_NE; }
440 <expr>"eq" { return T_OP_EQ; }
441 <expr>"in" { return T_OP_IN; }
443 <expr>"-"[a-zA-Z_][a-zA-Z_0-9]+ {
444 yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
449 yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1);
453 /* Apply subtitution to a string */
458 /* Join a list into a string */
463 /* Split a string (or list) into a(nother) list */
471 <expr>"true" { return T_TRUE; }
472 <expr>"false" { return T_FALSE; }
478 yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
486 yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
491 * These are parts of the grammar and are returned as is
498 * Anything else is an error
500 <INITIAL,expr>{ANY} {
501 PERROR_CHAR("Parse error near character ", yytext[0]);