2 * Copyright (C) 2016 Andre Noll <maan@tuebingen.mpg.de>
4 * Licensed under the LGPL v3, see http://www.gnu.org/licenses/lgpl-3.0.html
7 /* We don't want symbols to clash with those of other flex users. */
8 %option prefix="lls_yy"
10 /* Generate a scanner which is safe to use in multithreaded programs. */
13 /* To maintain state in a reentrant way. */
14 %option extra-type="struct lls_yy_config_file_extra *"
17 %option never-interactive
23 IDENTIFIER [a-zA-Z]+[a-zA-Z0-9_-]*
24 EQUALS [[:space:]]*=[[:space:]]*
25 OPTION [a-zA-Z]+[a-zA-Z0-9_-]*
33 #include "lopsub-internal.h"
36 struct lls_yy_config_file_extra {
42 static int add_option(yyscan_t yyscanner);
43 static int parse_arg(char **result, yyscan_t yyscanner);
44 static int yywrap(yyscan_t yyscanner) {return 1;}
49 /* skip comments and whitespace */
53 <INITIAL,SC_SCANNING>\[[[:space:]]*{IDENTIFIER}[[:space:]]*\][[:space:]]*\n {
55 const char *subcmd = yyget_extra(yyscanner)->subcmd;
57 assert(yytext[0] == '[');
60 for (i = 1; i < yyleng; i++)
61 if (!isspace(yytext[i]))
63 for (j = i; j < yyleng; j++)
64 if (yytext[j] == ']' || isspace(yytext[j]))
68 if (strcmp(yytext + i, subcmd))
74 <SC_SCANNING>{OPTION}[[:space:]]*\n add_option(yyscanner);
76 <SC_SCANNING>{OPTION}({EQUALS}|[[:space:]]+) {
77 int ret = add_option(yyscanner);
85 struct lls_yy_config_file_extra *extra = yyget_extra(yyscanner);
86 const char *opt = extra->argv[extra->argc - 1];
88 size_t opt_len = strlen(opt), arg_len;
89 int ret = parse_arg(&arg, yyscanner);
94 result = malloc(opt_len + arg_len + 2);
98 result[opt_len] = '=';
99 strcpy(result + opt_len + 1, arg);
101 result[opt_len + arg_len + 1] = '\0';
102 free(extra->argv[extra->argc - 1]);
103 extra->argv[extra->argc - 1] = result;
109 /* This rule runs iff none of the above patterns matched */
113 #include <sys/types.h>
114 #include <sys/stat.h>
118 static int expand_result(yyscan_t yyscanner)
120 struct lls_yy_config_file_extra *extra = yyget_extra(yyscanner);
121 int nargc = extra->argc + 1;
122 char **nrargv = realloc(extra->argv, (nargc + 1) * sizeof(char *));
127 extra->argv = nrargv;
128 extra->argv[extra->argc] = NULL;
132 static int add_option(yyscan_t yyscanner)
134 struct lls_yy_config_file_extra *extra = yyget_extra(yyscanner);
137 int len = yyget_leng(yyscanner);
138 char *narg, *text = yyget_text(yyscanner);
140 for (n = 0; n < len; n++)
141 if (!isalnum(text[n]) && !(text[n] == '-'))
144 ret = expand_result(yyscanner);
147 narg = malloc(n + 2 + 1);
150 narg[0] = narg[1] = '-';
151 memcpy(narg + 2, text, n);
153 extra->argv[extra->argc - 1] = narg;
157 static int parse_arg(char **result, yyscan_t yyscanner)
159 bool backslash = false, quote = false;
163 int len = yyget_leng(yyscanner);
164 char *text = yyget_text(yyscanner);
166 *result = malloc(len + 1);
169 for (in = text, out = *result; *in; in++) {
175 } else if (*in == 'n' || *in == 't') {
176 if (backslash) { /* \n or \t */
177 *out++ = (*in == 'n')? '\n' : '\t';
181 } else if (*in == '"') {
186 } else if (isspace(*in)) {
187 if (!backslash && !quote)
190 /* copy the character */
194 ret = -E_LLS_TRAILING_BACKSLASH;
197 ret = -E_LLS_UNMATCHED_QUOTE;
200 /* look at first non-space character */
206 ret = -E_LLS_TRAILING_GARBAGE;
211 return out - *result;
219 void lls_free_argv(char **argv)
225 for (i = 0; argv[i]; i++)
230 int lls_convert_config(const char *buf, size_t nbytes, const char *subcmd,
231 char ***result, char **errctx)
234 YY_BUFFER_STATE yybs;
236 struct lls_yy_config_file_extra extra;
243 extra.argv = malloc((extra.argc + 1) * sizeof(char *));
246 extra.argv[0] = strdup(__FUNCTION__);
247 if (!extra.argv[0]) {
251 extra.argv[1] = NULL;
252 extra.subcmd = subcmd;
254 ret = yylex_init_extra(&extra, &yyscanner);
259 yy_push_state(subcmd? INITIAL : SC_SCANNING, yyscanner);
260 yybs = yy_scan_bytes(buf, nbytes, yyscanner);
262 ret = -E_LLS_YY_SCAN;
265 ret = yylex(yyscanner);
269 *errctx = malloc(100);
271 sprintf(*errctx, "error at line %d",
272 yyget_lineno(yyscanner));
275 yy_delete_buffer(yybs, yyscanner);
277 yylex_destroy(yyscanner);
280 lls_free_argv(extra.argv);
282 *result = extra.argv;
291 char buf[100 * 1024];
292 int ret, len, i, argc;
295 ret = read(STDIN_FILENO, buf, sizeof(buf));
299 ret = lls_convert_config(buf, len, NULL, &argv, NULL);
303 for (i = 0; i < argc; i++)
304 printf("argv[%d]: %s\n", i, rargv[i]);