/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * ap_expr_scan.l, based on ssl_expr_scan.l from mod_ssl */ /* _________________________________________________________________ ** ** Expression Scanner ** _________________________________________________________________ */ %pointer %option batch %option never-interactive %option nodefault %option noyywrap %option reentrant %option bison-bridge %option warn %option noinput nounput noyy_top_state %option stack %x str %x var %x vararg %x regex regex_flags %{ #include "util_expr_private.h" #include "util_expr_parse.h" #undef YY_INPUT #define YY_INPUT(buf,result,max_size) \ { \ if ((result = MIN(max_size, yyextra->inputbuf \ + yyextra->inputlen \ - yyextra->inputptr)) <= 0) \ { \ result = YY_NULL; \ } \ else { \ memcpy(buf, yyextra->inputptr, result); \ yyextra->inputptr += result; \ } \ } #define YY_EXTRA_TYPE ap_expr_parse_ctx_t* #define PERROR(msg) do { yyextra->error2 = msg ; return T_ERROR; } while (0) #define str_ptr (yyextra->scan_ptr) #define str_buf (yyextra->scan_buf) #define str_del (yyextra->scan_del) #define STR_APPEND(c) do { \ *str_ptr++ = (c); \ if (str_ptr >= str_buf + sizeof(str_buf)) \ PERROR("String too long"); \ } while (0) %} %% char regex_buf[MAX_STRING_LEN]; char *regex_ptr = NULL; char regex_del = '\0'; %{ /* * Set initial state for string expressions */ if (yyextra->at_start) { yyextra->at_start = 0; if (yyextra->flags & AP_EXPR_FLAG_STRING_RESULT) { BEGIN(str); return T_EXPR_STRING; } else { return T_EXPR_BOOL; } } %} /* * Whitespaces */ [ \t\n]+ { /* NOP */ } /* * strings ("..." and '...') */ ["'] { str_ptr = str_buf; str_del = yytext[0]; BEGIN(str); return T_STR_BEGIN; } ["'] { if (yytext[0] == str_del) { if (YY_START == var) { PERROR("Unterminated variable in string"); } else if (str_ptr == str_buf) { BEGIN(INITIAL); return T_STR_END; } else { /* return what we have so far and scan delimiter again */ *str_ptr = '\0'; yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf); yyless(0); str_ptr = str_buf; return T_STRING; } } else { STR_APPEND(yytext[0]); } } \n { PERROR("Unterminated string or variable"); } <> { PERROR("Unterminated string or variable"); } <> { if (!(yyextra->flags & AP_EXPR_FLAG_STRING_RESULT)) { PERROR("Unterminated string or variable"); } else { *str_ptr = '\0'; yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf); str_ptr = str_buf; BEGIN(INITIAL); return T_STRING; } } \\[0-7]{1,3} { int result; (void)sscanf(yytext+1, "%o", &result); if (result > 0xff) { PERROR("Escape sequence out of bound"); } else { STR_APPEND(result); } } \\[0-9]+ { PERROR("Bad escape sequence"); } \\n { STR_APPEND('\n'); } \\r { STR_APPEND('\r'); } \\t { STR_APPEND('\t'); } \\b { STR_APPEND('\b'); } \\f { STR_APPEND('\f'); } \\(.|\n) { STR_APPEND(yytext[1]); } /* regexp backref inside string/arg */ [$][0-9] { if (str_ptr != str_buf) { /* return what we have so far and scan '$x' again */ *str_ptr = '\0'; yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf); str_ptr = str_buf; yyless(0); return T_STRING; } else { yylval->num = yytext[1] - '0'; return T_REGEX_BACKREF; } } [^\\\n"'%}$]+ { char *cp = yytext; while (*cp != '\0') { STR_APPEND(*cp); cp++; } } /* variable inside string/arg */ %\{ { if (str_ptr != str_buf) { /* return what we have so far and scan '%{' again */ *str_ptr = '\0'; yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf); yyless(0); str_ptr = str_buf; return T_STRING; } else { yy_push_state(var, yyscanner); return T_VAR_BEGIN; } } [%$] { STR_APPEND(yytext[0]); } [%}$] { STR_APPEND(yytext[0]); } %\{ { yy_push_state(var, yyscanner); return T_VAR_BEGIN; } [$][0-9] { yylval->num = yytext[1] - '0'; return T_REGEX_BACKREF; } /* * fixed name variable expansion %{XXX} and function call in %{func:arg} syntax */ [a-zA-Z][a-zA-Z0-9_]* { yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); return T_ID; } \} { yy_pop_state(yyscanner); return T_VAR_END; } : { BEGIN(vararg); return yytext[0]; } .|\n { char *msg = apr_psprintf(yyextra->pool, "Invalid character in variable name '%c'", yytext[0]); PERROR(msg); } \} { if (str_ptr != str_buf) { /* return what we have so far and scan '}' again */ *str_ptr = '\0'; yylval->cpVal = apr_pstrdup(yyextra->pool, str_buf); str_ptr = str_buf; yyless(0); return T_STRING; } else { yy_pop_state(yyscanner); return T_VAR_END; } } /* * Regular Expression */ "m"[/#$%^,;:_\?\|\^\-\!\.\'\"] { regex_del = yytext[1]; regex_ptr = regex_buf; BEGIN(regex); } "/" { regex_del = yytext[0]; regex_ptr = regex_buf; BEGIN(regex); } .|\n { if (yytext[0] == regex_del) { *regex_ptr = '\0'; BEGIN(regex_flags); } else { *regex_ptr++ = yytext[0]; if (regex_ptr >= regex_buf + sizeof(regex_buf)) PERROR("Regexp too long"); } } i { yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); BEGIN(INITIAL); return T_REGEX_I; } .|\n { yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); yyless(0); BEGIN(INITIAL); return T_REGEX; } <> { yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf); BEGIN(INITIAL); return T_REGEX; } /* * Operators */ ==? { return T_OP_STR_EQ; } "!=" { return T_OP_STR_NE; } "<" { return T_OP_STR_LT; } "<=" { return T_OP_STR_LE; } ">" { return T_OP_STR_GT; } ">=" { return T_OP_STR_GE; } "=~" { return T_OP_REG; } "!~" { return T_OP_NRE; } "and" { return T_OP_AND; } "&&" { return T_OP_AND; } "or" { return T_OP_OR; } "||" { return T_OP_OR; } "not" { return T_OP_NOT; } "!" { return T_OP_NOT; } "." { return T_OP_CONCAT; } "-in" { return T_OP_IN; } "-eq" { return T_OP_EQ; } "-ne" { return T_OP_NE; } "-ge" { return T_OP_GE; } "-le" { return T_OP_LE; } "-gt" { return T_OP_GT; } "-lt" { return T_OP_LT; } /* for compatibility with ssl_expr */ "lt" { return T_OP_LT; } "le" { return T_OP_LE; } "gt" { return T_OP_GT; } "ge" { return T_OP_GE; } "ne" { return T_OP_NE; } "eq" { return T_OP_EQ; } "in" { return T_OP_IN; } "-"[a-zA-Z_] { yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1); return T_OP_UNARY; } "-"[a-zA-Z_][a-zA-Z_0-9]+ { yylval->cpVal = apr_pstrdup(yyextra->pool, yytext + 1); return T_OP_BINARY; } /* * Specials */ "true" { return T_TRUE; } "false" { return T_FALSE; } /* * Digits */ -?[0-9]+ { yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); return T_DIGIT; } /* * Identifiers */ [a-zA-Z][a-zA-Z0-9_]* { yylval->cpVal = apr_pstrdup(yyextra->pool, yytext); return T_ID; } /* * These are parts of the grammar and are returned as is */ [(){},:] { return yytext[0]; } /* * Anything else is an error */ .|\n { char *msg = apr_psprintf(yyextra->pool, "Parse error near '%c'", yytext[0]); PERROR(msg); } %%