summaryrefslogtreecommitdiffstats
path: root/server/util_expr_scan.l
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--server/util_expr_scan.l400
1 files changed, 400 insertions, 0 deletions
diff --git a/server/util_expr_scan.l b/server/util_expr_scan.l
new file mode 100644
index 0000000..513236a
--- /dev/null
+++ b/server/util_expr_scan.l
@@ -0,0 +1,400 @@
+/* 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;
+}
+<str>["'] {
+ 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]);
+ }
+}
+<str,var,vararg>\n {
+ PERROR("Unterminated string or variable");
+}
+<var,vararg><<EOF>> {
+ PERROR("Unterminated string or variable");
+}
+<str><<EOF>> {
+ 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;
+ }
+}
+
+<str,vararg>\\[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);
+ }
+}
+<str,vararg>\\[0-9]+ {
+ PERROR("Bad escape sequence");
+}
+<str,vararg>\\n { STR_APPEND('\n'); }
+<str,vararg>\\r { STR_APPEND('\r'); }
+<str,vararg>\\t { STR_APPEND('\t'); }
+<str,vararg>\\b { STR_APPEND('\b'); }
+<str,vararg>\\f { STR_APPEND('\f'); }
+<str,vararg>\\(.|\n) { STR_APPEND(yytext[1]); }
+
+ /* regexp backref inside string/arg */
+<str,vararg>[$][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;
+ }
+}
+
+<str,vararg>[^\\\n"'%}$]+ {
+ char *cp = yytext;
+ while (*cp != '\0') {
+ STR_APPEND(*cp);
+ cp++;
+ }
+}
+
+ /* variable inside string/arg */
+<str,vararg>%\{ {
+ 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;
+ }
+}
+
+<vararg>[%$] {
+ STR_APPEND(yytext[0]);
+}
+
+<str>[%}$] {
+ 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
+ */
+<var>[a-zA-Z][a-zA-Z0-9_]* {
+ yylval->cpVal = apr_pstrdup(yyextra->pool, yytext);
+ return T_ID;
+}
+
+<var>\} {
+ yy_pop_state(yyscanner);
+ return T_VAR_END;
+}
+
+<var>: {
+ BEGIN(vararg);
+ return yytext[0];
+}
+
+<var>.|\n {
+ char *msg = apr_psprintf(yyextra->pool,
+ "Invalid character in variable name '%c'", yytext[0]);
+ PERROR(msg);
+}
+
+<vararg>\} {
+ 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);
+}
+<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");
+ }
+}
+<regex_flags>i {
+ yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+ BEGIN(INITIAL);
+ return T_REGEX_I;
+}
+<regex_flags>.|\n {
+ yylval->cpVal = apr_pstrdup(yyextra->pool, regex_buf);
+ yyless(0);
+ BEGIN(INITIAL);
+ return T_REGEX;
+}
+<regex_flags><<EOF>> {
+ 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);
+}
+
+%%
+
+