/* SPDX-License-Identifier: GPL-2.0 */
%{
 #include "emp_ematch.tab.h"
 #include "m_ematch.h"

 extern int ematch_argc;
 extern char **ematch_argv;

 #define yylval ematch_lval

 #define NEXT_EM_ARG() do { ematch_argc--; ematch_argv++; } while(0);

 #define YY_INPUT(buf, result, max_size)				\
 {									\
 next:									\
 	if (ematch_argc <= 0)						\
		result = YY_NULL;					\
	else if (**ematch_argv == '\0') {				\
		NEXT_EM_ARG();						\
		goto next;						\
	} else {							\
		if (max_size <= strlen(*ematch_argv) + 1) {		\
			fprintf(stderr, "match argument too long.\n");	\
			result = YY_NULL;				\
		} else {						\
			strcpy(buf, *ematch_argv);			\
			result = strlen(*ematch_argv) + 1;		\
			buf[result-1] = ' ';				\
			buf[result] = '\0';				\
			NEXT_EM_ARG();					\
		}							\
	}								\
 }

 static void __attribute__ ((unused)) yyunput (int c,char *buf_ptr  );
 static void __attribute__ ((unused)) yy_push_state (int  new_state );
 static void __attribute__ ((unused)) yy_pop_state  (void);
 static int  __attribute__ ((unused)) yy_top_state (void );

 static char *strbuf;
 static unsigned int strbuf_size;
 static unsigned int strbuf_index;

 static void strbuf_enlarge(void)
 {
 	strbuf_size += 512;
 	strbuf = realloc(strbuf, strbuf_size);
 }

 static void strbuf_append_char(char c)
 {
 	while (strbuf_index >= strbuf_size)
 		strbuf_enlarge();
 	strbuf[strbuf_index++] = c;
 }

 static void strbuf_append_charp(char *s)
 {
 	while (strbuf_index >= strbuf_size)
 		strbuf_enlarge();
 	memcpy(strbuf + strbuf_index, s, strlen(s));
 	strbuf_index += strlen(s);
 }

%}

%x lexstr

%option 8bit stack warn noyywrap prefix="ematch_"
%%
[ \t\r\n]+

\"					{
						if (strbuf == NULL) {
							strbuf_size = 512;
							strbuf = calloc(1, strbuf_size);
							if (strbuf == NULL)
								return ERROR;
						}
						strbuf_index = 0;

						BEGIN(lexstr);
					}

<lexstr>\"					{
						BEGIN(INITIAL);
						yylval.b = bstr_new(strbuf, strbuf_index);
						yylval.b->quoted = 1;
						return ATTRIBUTE;
					}

<lexstr>\\[0-7]{1,3}			{ /* octal escape sequence */
						int res;

						sscanf(yytext + 1, "%o", &res);
						if (res > 0xFF) {
							fprintf(stderr, "error: octal escape sequence" \
							" out of range\n");
							return ERROR;
						}
						strbuf_append_char((unsigned char) res);
					}

<lexstr>\\[0-9]+				{ /* catch wrong octal escape seq. */
						fprintf(stderr, "error: invalid octale escape sequence\n");
						return ERROR;
					}

<lexstr>\\x[0-9a-fA-F]{1,2}		{
						int res;

						sscanf(yytext + 2, "%x", &res);

						if (res > 0xFF) {
							fprintf(stderr, "error: hexadecimal escape " \
							"sequence out of range\n");
							return ERROR;
						}
						strbuf_append_char((unsigned char) res);
					}

<lexstr>\\n				strbuf_append_char('\n');
<lexstr>\\r				strbuf_append_char('\r');
<lexstr>\\t				strbuf_append_char('\t');
<lexstr>\\v				strbuf_append_char('\v');
<lexstr>\\b				strbuf_append_char('\b');
<lexstr>\\f				strbuf_append_char('\f');
<lexstr>\\a				strbuf_append_char('\a');

<lexstr>\\(.|\n)			strbuf_append_char(yytext[1]);
<lexstr>[^\\\n\"]+			strbuf_append_charp(yytext);

[aA][nN][dD]				return AND;
[oO][rR]				return OR;
[nN][oO][tT]				return NOT;
"("					|
")"					{
						return yylval.i = *yytext;
					}
[^" \t\r\n()][^ \t\r\n()]*		{
						yylval.b = bstr_alloc(yytext);
						if (yylval.b == NULL)
							return ERROR;
						return ATTRIBUTE;
					}
%%
