]> git.tuebingen.mpg.de Git - lopsub.git/blob - config_file.l
b6eff7cc5bd09ae4f4d257ee76be4a4d9279e99e
[lopsub.git] / config_file.l
1 /*
2  * Copyright (C) 2016 Andre Noll <maan@tuebingen.mpg.de>
3  *
4  * Licensed under the LGPL v3, see http://www.gnu.org/licenses/lgpl-3.0.html
5  */
6
7  /* We don't want symbols to clash with those of other flex users. */
8 %option prefix="lls_yy"
9
10 %option stack
11 %option never-interactive
12 %option yylineno
13
14 %x SC_ARG
15 %s SC_SCANNING
16
17 IDENTIFIER [a-zA-Z]+[a-zA-Z0-9_-]*
18 EQUALS [[:space:]]*=[[:space:]]*
19 OPTION [a-zA-Z]+[a-zA-Z0-9_-]*
20
21 %{
22         #include <stdlib.h>
23         #include <ctype.h>
24         #include <assert.h>
25         #include <stdbool.h>
26         #include <inttypes.h>
27         #include "lopsub-internal.h"
28         #include "lopsub.h"
29
30         static int rargc;
31         static char **rargv;
32         static const char *subcommand;
33
34         static int yywrap(void) {return 1;}
35         static int expand_result(void)
36         {
37                 int nargc = rargc + 1;
38                 char **nrargv = realloc(rargv, (nargc + 1) * sizeof(char *));
39
40                 if (!nrargv)
41                         return -E_LLS_NOMEM;
42                 rargc = nargc;
43                 rargv = nrargv;
44                 rargv[rargc] = NULL;
45                 return 1;
46         }
47
48         static int add_option(void)
49         {
50                 int ret;
51                 unsigned n;
52
53                 for (n = 0; n < yyleng; n++)
54                         if (!isalnum(yytext[n]) && !(yytext[n] == '-'))
55                                 break;
56                 assert(n > 0);
57                 ret = expand_result();
58                 if (ret < 0)
59                         return ret;
60                 rargv[rargc - 1] = malloc(n + 2 + 1);
61                 if (!rargv[rargc - 1])
62                         return -E_LLS_NOMEM;
63                 rargv[rargc - 1][0] = rargv[rargc - 1][1] = '-';
64                 memcpy(rargv[rargc - 1] + 2, yytext, n);
65                 rargv[rargc - 1][n + 2] = '\0';
66                 return 1;
67         }
68
69         static int parse_arg(char **result)
70         {
71                 bool backslash = false, quote = false;
72                 const char *in;
73                 char *out;
74                 int ret;
75
76                 *result = malloc(yyleng + 1);
77                 if (!*result)
78                         return -E_LLS_NOMEM;
79                 for (in = yytext, out = *result; *in; in++) {
80                         if (*in == '\\') {
81                                 if (!backslash) {
82                                         backslash = true;
83                                         continue;
84                                 }
85                         } else if (*in == 'n' || *in == 't') {
86                                 if (backslash) { /* \n or \t */
87                                         *out++ = (*in == 'n')? '\n' : '\t';
88                                         backslash = false;
89                                         continue;
90                                 }
91                         } else if (*in == '"') {
92                                 if (!backslash) {
93                                         quote = !quote;
94                                         continue;
95                                 }
96                         } else if (isspace(*in)) {
97                                 if (!backslash && !quote)
98                                         break;
99                         }
100                         /* copy the character */
101                         *out++ = *in;
102                         backslash = false;
103                 }
104                 ret = -E_LLS_TRAILING_BACKSLASH;
105                 if (backslash)
106                         goto fail;
107                 ret = -E_LLS_UNMATCHED_QUOTE;
108                 if (quote)
109                         goto fail;
110                 /* look at first non-space character */
111                 for (; *in; in++) {
112                         if (isspace(*in))
113                                 continue;
114                         if (*in == '#')
115                                 break;
116                         ret = -E_LLS_TRAILING_GARBAGE;
117                         goto fail;
118                 }
119                 /* success */
120                 *out = '\0';
121                 return out - *result;
122         fail:
123                 assert(ret < 0);
124                 free(*result);
125                 *result = NULL;
126                 return ret;
127         }
128 %}
129
130 %%
131
132  /* skip comments and whitespace */
133 ^[[:space:]]*#.*\n ;
134 [[:space:]]|\n+ ;
135
136 <INITIAL,SC_SCANNING>\[[[:space:]]*{IDENTIFIER}[[:space:]]*\][[:space:]]*\n {
137         int i, j;
138
139         assert(yytext[0] == '[');
140         if (!subcommand)
141                 return 0;
142         for (i = 1; i < yyleng; i++)
143                 if (!isspace(yytext[i]))
144                         break;
145         for (j = i; j < yyleng; j++)
146                 if (yytext[j] == ']' || isspace(yytext[j]))
147                         break;
148         assert(j < yyleng);
149         yytext[j] = '\0';
150         if (strcmp(yytext + i, subcommand))
151                 BEGIN(INITIAL);
152         else
153                 BEGIN(SC_SCANNING);
154 }
155
156 <SC_SCANNING>{OPTION}[[:space:]]*\n add_option();
157
158 <SC_SCANNING>{OPTION}({EQUALS}|[[:space:]]+) {
159         int ret = add_option();
160
161         if (ret < 0)
162                 return ret;
163         BEGIN(SC_ARG);
164 }
165
166 <SC_ARG>.*\n {
167         const char *opt = rargv[rargc - 1];
168         char *arg, *result;
169         size_t opt_len = strlen(opt), arg_len;
170         int ret = parse_arg(&arg);
171
172         if (ret < 0)
173                 return ret;
174         arg_len = ret;
175         result = malloc(opt_len + arg_len + 2);
176         if (!result)
177                 return -E_LLS_NOMEM;
178         strcpy(result, opt);
179         result[opt_len] = '=';
180         strcpy(result + opt_len + 1, arg);
181         free(arg);
182         result[opt_len + arg_len + 1] = '\0';
183         free(rargv[rargc - 1]);
184         rargv[rargc - 1] = result;
185         BEGIN(SC_SCANNING);
186 }
187
188 <INITIAL>.*\n {}
189
190  /* This rule runs iff none of the above patterns matched */
191 . {return -1;}
192 %%
193
194 #include <sys/types.h>
195 #include <sys/stat.h>
196 #include <fcntl.h>
197 #include <stdio.h>
198
199 int lls_convert_config(const char *buf, size_t nbytes, const char *subcmd,
200                  char ***result, char **errctx)
201 {
202         int ret;
203         YY_BUFFER_STATE yybs;
204
205         *result = NULL;
206         if (errctx)
207                 *errctx = NULL;
208         subcommand = subcmd;
209         if (!subcmd)
210                 BEGIN(SC_SCANNING);
211         else
212                 BEGIN(INITIAL);
213         yybs = yy_scan_bytes(buf, nbytes);
214         if (!yybs)
215                 return -E_LLS_YY_SCAN;
216         rargc = 1;
217         rargv = malloc((rargc + 1) * sizeof(char *));
218         if (!rargv)
219                 return -E_LLS_NOMEM;
220         rargv[0] = strdup(__FUNCTION__);
221         if (!rargv[0]) {
222                 free(rargv);
223                 return -E_LLS_NOMEM;
224         }
225         rargv[1] = NULL;
226         ret = yylex();
227         yy_delete_buffer(yybs);
228         if (ret >= 0) {
229                 *result = rargv;
230                 return rargc;
231         }
232         if (errctx) {
233                 *errctx = malloc(100);
234                 if (*errctx)
235                         sprintf(*errctx, "error at line %d", yyget_lineno());
236         }
237         for (; rargc >= 0; rargc--)
238                 free(rargv[rargc]);
239         free(rargv);
240         *result = NULL;
241         return -E_LLS_YY_LEX;
242 }
243
244 void lls_free_argv(char **argv)
245 {
246         int i;
247
248         if (!argv)
249                 return;
250         for (i = 0; argv[i]; i++)
251                 free(argv[i]);
252         free(argv);
253 }
254 #if 0
255 int main(void)
256 {
257         char buf[100 * 1024];
258         int ret, len, i, argc;
259         char **argv;
260
261         ret = read(STDIN_FILENO, buf, sizeof(buf));
262         if (ret <= 0)
263                 exit(EXIT_FAILURE);
264         len = ret;
265         ret = lls_convert_config(buf, len, NULL, &argv, NULL);
266         if (ret < 0)
267                 exit(EXIT_FAILURE);
268         argc = ret;
269         for (i = 0; i < argc; i++)
270                 printf("argv[%d]: %s\n", i, rargv[i]);
271         return EXIT_SUCCESS;
272 }
273 #endif