/*
* Copyright (C) 2016 Andre Noll <maan@tuebingen.mpg.de>
*
- * Licensed under the LGPL v3, see http://www.gnu.org/licenses/lgpl-3.0.html
+ * Licensed under the LGPL v3, see https://www.gnu.org/licenses/lgpl-3.0.html
*/
-%option noyywrap
+ /* We don't want symbols to clash with those of other flex users. */
+%option prefix="lls_yy"
+
+ /* Generate a scanner which is safe to use in multithreaded programs. */
+%option reentrant
+
+ /* To maintain state in a reentrant way. */
+%option extra-type="struct lls_yy_config_file_extra *"
+
%option stack
%option never-interactive
%option yylineno
%s SC_SCANNING
IDENTIFIER [a-zA-Z]+[a-zA-Z0-9_-]*
-EQUALS [[:space:]]*=[[:space:]]*
+EQUALS [[:blank:]]*=[[:blank:]]*
OPTION [a-zA-Z]+[a-zA-Z0-9_-]*
%{
#include "lopsub-internal.h"
#include "lopsub.h"
- static int rargc;
- static char **rargv;
- static const char *subcommand;
-
- static int expand_result(void)
- {
- int nargc = rargc + 1;
- char **nrargv = realloc(rargv, (nargc + 1) * sizeof(char *));
-
- if (!nrargv)
- return -E_LLS_NOMEM;
- rargc = nargc;
- rargv = nrargv;
- rargv[rargc] = NULL;
- return 1;
- }
-
- static int add_option(void)
- {
- int ret;
- unsigned n;
+ struct lls_yy_config_file_extra {
+ int argc;
+ char **argv;
+ const char *subcmd;
+ };
- for (n = 0; n < yyleng; n++)
- if (!isalnum(yytext[n]) && !(yytext[n] == '-'))
- break;
- assert(n > 0);
- ret = expand_result();
- if (ret < 0)
- return ret;
- rargv[rargc - 1] = malloc(n + 2 + 1);
- if (!rargv[rargc - 1])
- return -E_LLS_NOMEM;
- rargv[rargc - 1][0] = rargv[rargc - 1][1] = '-';
- memcpy(rargv[rargc - 1] + 2, yytext, n);
- rargv[rargc - 1][n + 2] = '\0';
- return 1;
- }
-
- static int parse_arg(char **result)
- {
- bool backslash = false, quote = false;
- const char *in;
- char *out;
- int ret;
-
- *result = malloc(yyleng + 1);
- if (!*result)
- return -E_LLS_NOMEM;
- for (in = yytext, out = *result; *in; in++) {
- if (*in == '\\') {
- if (!backslash) {
- backslash = true;
- continue;
- }
- } else if (*in == 'n' || *in == 't') {
- if (backslash) { /* \n or \t */
- *out++ = (*in == 'n')? '\n' : '\t';
- backslash = false;
- continue;
- }
- } else if (*in == '"') {
- if (!backslash) {
- quote = !quote;
- continue;
- }
- } else if (isspace(*in)) {
- if (!backslash && !quote)
- break;
- }
- /* copy the character */
- *out++ = *in;
- backslash = false;
- }
- ret = -E_LLS_TRAILING_BACKSLASH;
- if (backslash)
- goto fail;
- ret = -E_LLS_UNMATCHED_QUOTE;
- if (quote)
- goto fail;
- /* look at first non-space character */
- for (; *in; in++) {
- if (isspace(*in))
- continue;
- if (*in == '#')
- break;
- ret = -E_LLS_TRAILING_GARBAGE;
- goto fail;
- }
- /* success */
- *out = '\0';
- return out - *result;
- fail:
- assert(ret < 0);
- free(*result);
- *result = NULL;
- return ret;
- }
+ static int add_option(yyscan_t yyscanner);
+ static int parse_arg(char **result, yyscan_t yyscanner);
+ static int yywrap(yyscan_t yyscanner) {return 1;}
%}
%%
/* skip comments and whitespace */
-^[[:space:]]*#.*\n ;
-[[:space:]]|\n+ ;
+^[[:blank:]]*#.*\n ;
+[[:blank:]]|\n+ ;
-<INITIAL,SC_SCANNING>\[[[:space:]]*{IDENTIFIER}[[:space:]]*\][[:space:]]*\n {
+<INITIAL,SC_SCANNING>\[[[:blank:]]*{IDENTIFIER}[[:blank:]]*\][[:blank:]]*\n {
int i, j;
+ const char *subcmd = yyget_extra(yyscanner)->subcmd;
assert(yytext[0] == '[');
- if (!subcommand)
+ if (!subcmd)
return 0;
for (i = 1; i < yyleng; i++)
if (!isspace(yytext[i]))
break;
assert(j < yyleng);
yytext[j] = '\0';
- if (strcmp(yytext + i, subcommand))
+ if (strcmp(yytext + i, subcmd))
BEGIN(INITIAL);
else
BEGIN(SC_SCANNING);
}
-<SC_SCANNING>{OPTION}[[:space:]]*\n add_option();
+<SC_SCANNING>{OPTION}[[:blank:]]*\n add_option(yyscanner);
-<SC_SCANNING>{OPTION}({EQUALS}|[[:space:]]+) {
- int ret = add_option();
+<SC_SCANNING>{OPTION}({EQUALS}|[[:blank:]]+) {
+ int ret = add_option(yyscanner);
if (ret < 0)
return ret;
}
<SC_ARG>.*\n {
- const char *opt = rargv[rargc - 1];
+ struct lls_yy_config_file_extra *extra = yyget_extra(yyscanner);
+ const char *opt = extra->argv[extra->argc - 1];
char *arg, *result;
size_t opt_len = strlen(opt), arg_len;
- int ret = parse_arg(&arg);
+ int ret = parse_arg(&arg, yyscanner);
if (ret < 0)
return ret;
strcpy(result + opt_len + 1, arg);
free(arg);
result[opt_len + arg_len + 1] = '\0';
- free(rargv[rargc - 1]);
- rargv[rargc - 1] = result;
+ free(extra->argv[extra->argc - 1]);
+ extra->argv[extra->argc - 1] = result;
BEGIN(SC_SCANNING);
}
#include <fcntl.h>
#include <stdio.h>
-int lls_convert_config(const char *buf, size_t nbytes, const char *subcmd,
- char ***result, char **errctx)
+static int expand_result(yyscan_t yyscanner)
{
+ struct lls_yy_config_file_extra *extra = yyget_extra(yyscanner);
+ int nargc = extra->argc + 1;
+ char **nrargv = realloc(extra->argv, (nargc + 1) * sizeof(char *));
+
+ if (!nrargv)
+ return -E_LLS_NOMEM;
+ extra->argc = nargc;
+ extra->argv = nrargv;
+ extra->argv[extra->argc] = NULL;
+ return 1;
+}
+
+static int add_option(yyscan_t yyscanner)
+{
+ struct lls_yy_config_file_extra *extra = yyget_extra(yyscanner);
int ret;
- YY_BUFFER_STATE yybs;
+ unsigned n;
+ int len = yyget_leng(yyscanner);
+ char *narg, *text = yyget_text(yyscanner);
- *result = NULL;
- if (errctx)
- *errctx = NULL;
- subcommand = subcmd;
- if (!subcmd)
- BEGIN(SC_SCANNING);
- else
- BEGIN(INITIAL);
- yybs = yy_scan_bytes(buf, nbytes);
- if (!yybs)
- return -E_LLS_YY_SCAN;
- rargc = 1;
- rargv = malloc((rargc + 1) * sizeof(char *));
- if (!rargv)
+ for (n = 0; n < len; n++)
+ if (!isalnum(text[n]) && !(text[n] == '-'))
+ break;
+ assert(n > 0);
+ ret = expand_result(yyscanner);
+ if (ret < 0)
+ return ret;
+ narg = malloc(n + 2 + 1);
+ if (!narg)
return -E_LLS_NOMEM;
- rargv[0] = strdup(__FUNCTION__);
- if (!rargv[0]) {
- free(rargv);
+ narg[0] = narg[1] = '-';
+ memcpy(narg + 2, text, n);
+ narg[n + 2] = '\0';
+ extra->argv[extra->argc - 1] = narg;
+ return 1;
+}
+
+static int parse_arg(char **result, yyscan_t yyscanner)
+{
+ bool backslash = false, quote = false;
+ const char *in;
+ char *out;
+ int ret;
+ int len = yyget_leng(yyscanner);
+ char *text = yyget_text(yyscanner);
+
+ *result = malloc(len + 1);
+ if (!*result)
return -E_LLS_NOMEM;
+ for (in = text, out = *result; *in; in++) {
+ if (*in == '\\') {
+ if (!backslash) {
+ backslash = true;
+ continue;
+ }
+ } else if (*in == 'n' || *in == 't') {
+ if (backslash) { /* \n or \t */
+ *out++ = (*in == 'n')? '\n' : '\t';
+ backslash = false;
+ continue;
+ }
+ } else if (*in == '"') {
+ if (!backslash) {
+ quote = !quote;
+ continue;
+ }
+ } else if (isspace(*in)) {
+ if (!backslash && !quote)
+ break;
+ }
+ /* copy the character */
+ *out++ = *in;
+ backslash = false;
}
- rargv[1] = NULL;
- ret = yylex();
- yy_delete_buffer(yybs);
- if (ret >= 0) {
- *result = rargv;
- return rargc;
- }
- if (errctx) {
- *errctx = malloc(100);
- if (*errctx)
- sprintf(*errctx, "error at line %d", yyget_lineno());
+ ret = -E_LLS_TRAILING_BACKSLASH;
+ if (backslash)
+ goto fail;
+ ret = -E_LLS_UNMATCHED_QUOTE;
+ if (quote)
+ goto fail;
+ /* look at first non-space character */
+ for (; *in; in++) {
+ if (isspace(*in))
+ continue;
+ if (*in == '#')
+ break;
+ ret = -E_LLS_TRAILING_GARBAGE;
+ goto fail;
}
- for (; rargc >= 0; rargc--)
- free(rargv[rargc]);
- free(rargv);
+ /* success */
+ *out = '\0';
+ return out - *result;
+fail:
+ assert(ret < 0);
+ free(*result);
*result = NULL;
- return -E_LLS_YY_LEX;
+ return ret;
}
void lls_free_argv(char **argv)
free(argv[i]);
free(argv);
}
+
+int lls_convert_config(const char *buf, size_t nbytes, const char *subcmd,
+ char ***result, char **errctx)
+{
+ int ret;
+ YY_BUFFER_STATE yybs;
+ yyscan_t yyscanner;
+ struct lls_yy_config_file_extra extra;
+
+ *result = NULL;
+ if (errctx)
+ *errctx = NULL;
+
+ extra.argc = 1;
+ extra.argv = malloc((extra.argc + 1) * sizeof(char *));
+ if (!extra.argv)
+ return -E_LLS_NOMEM;
+ extra.argv[0] = strdup(__FUNCTION__);
+ if (!extra.argv[0]) {
+ free(extra.argv);
+ return -E_LLS_NOMEM;
+ }
+ extra.argv[1] = NULL;
+ extra.subcmd = subcmd;
+
+ ret = yylex_init_extra(&extra, &yyscanner);
+ if (ret != 0) {
+ ret = -E_LLS_NOMEM;
+ goto free_argv;
+ }
+ yy_push_state(subcmd? INITIAL : SC_SCANNING, yyscanner);
+ yybs = yy_scan_bytes(buf, nbytes, yyscanner);
+ if (!yybs) {
+ ret = -E_LLS_YY_SCAN;
+ goto destroy;
+ }
+ ret = yylex(yyscanner);
+ if (ret < 0) {
+ ret = -E_LLS_YY_LEX;
+ if (errctx) {
+ *errctx = malloc(100);
+ if (*errctx)
+ sprintf(*errctx, "yylex error");
+ }
+ }
+ yy_delete_buffer(yybs, yyscanner);
+destroy:
+ yylex_destroy(yyscanner);
+free_argv:
+ if (ret < 0)
+ lls_free_argv(extra.argv);
+ else {
+ *result = extra.argv;
+ ret = extra.argc;
+ }
+ return ret;
+}
+
#if 0
+/* flex -o t.c config_file.l && cc -o tcf t.c */
int main(void)
{
char buf[100 * 1024];
exit(EXIT_FAILURE);
argc = ret;
for (i = 0; i < argc; i++)
- printf("argv[%d]: %s\n", i, rargv[i]);
+ printf("argv[%d]: %s\n", i, argv[i]);
return EXIT_SUCCESS;
}
#endif