/* 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;
}
}
}