/* This file is part of varnish-mib Copyright (C) 2018 Sergey Poznyakoff Varnish-mib is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Varnish-mib is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with varnish-mib. If not, see . */ %option nounput %option noinput %{ #include "backend.h" enum { T_BOGUS = 256, T_IDENT, T_NUMBER, T_STRING, T_BACKEND, T_HOST, T_PORT }; static char const *input_string; static size_t input_len; static size_t input_pos; static char const *string_start; static size_t current_pos; #define YY_INPUT(buf,result,max_size) \ do { \ size_t n = input_len - input_pos; \ if (n > max_size) \ n = max_size; \ memcpy(buf, input_string, n); \ input_pos += n; \ result = n; \ } while (0) #define YY_USER_ACTION \ current_pos += yyleng; #define YY_DECL static int yylex(void) static int yywrap(void); static char const * input_point(void) { return input_string + current_pos; } #define YYSTYPE be_string_t #define YYSTYPE_INITIALIZER { NULL, 0 } static YYSTYPE yylval; %} %x COMMENT STR %% /* C-style comments */ "/*" BEGIN(COMMENT); [^*]* /* eat anything that's not a '*' */ "*"+[^*/]* /* eat up '*'s not followed by '/'s */ "*"+"/" BEGIN(INITIAL); /* Single-line comments */ "//".*\n ; #.*\n ; /* Multi-line strings */ "{\"" { BEGIN(STR); string_start = input_point(); } [^\"]* /* eat anything that's not a '"' */ "\""+[^"}]* /* eat up '"'s not followed by '}'s */ "\""+"}" { BEGIN(INITIAL); yylval.start = string_start; yylval.len = input_point() - yylval.start - 2; return T_STRING; } /* Single-line strings */ \".*\" { yylval.start = input_point() - yyleng + 1; yylval.len = yyleng - 2; return T_STRING; } backend return T_BACKEND; ".host" return T_HOST; ".port" return T_PORT; "{"|"}"|"="|";" return yytext[0]; [a-zA-Z_][a-zA-Z0-9_.]+ { yylval.start = input_point() - yyleng; yylval.len = yyleng; return T_IDENT; } [0-9]+ return T_NUMBER; [ \t\n]+ ; . return T_BOGUS; %% int yywrap(void) { return 1; } static void set_input(char const *str, size_t len) { input_string = str; input_len = len; input_pos = 0; current_pos = 0; } static int brace_nesting; static void read_backend(regfun_t regfun, void *d) { int c; int in_statement; YYSTYPE label, host = YYSTYPE_INITIALIZER, port = YYSTYPE_INITIALIZER; if ((c = yylex()) != T_IDENT && c != T_STRING) return; label = yylval; if ((c = yylex()) != '{') return; brace_nesting++; in_statement = 0; while (brace_nesting == 1) { c = yylex(); if (c == 0) break; else if (c == '{') brace_nesting++; else if (c == '}') brace_nesting++; else if (in_statement) { if (c == ';') in_statement = 0; } else { in_statement = 1; if (c == T_HOST || c == T_PORT) { YYSTYPE *stk = c == T_HOST ? &host : &port; in_statement = 1; if ((c = yylex()) == '=') { c = yylex(); if (c == T_STRING || c == T_IDENT) { *stk = yylval; } } } } } regfun(&label, &host, &port, d); } void backend_parser(const char *str, size_t len, regfun_t regfun, void *d) { int c; set_input(str, len); brace_nesting = 0; while ((c = yylex())) { if (brace_nesting == 0) { if (c == T_BACKEND) { read_backend(regfun, d); } } switch (c) { case '{': brace_nesting++; break; case '}': brace_nesting--; break; } } }