File: | src/usr.bin/lex/filter.c |
Warning: | line 368, column 4 Value stored to 'num' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: filter.c,v 1.9 2017/08/30 02:54:07 lteo Exp $ */ |
2 | |
3 | /* filter - postprocessing of flex output through filters */ |
4 | |
5 | /* This file is part of flex. */ |
6 | |
7 | /* Redistribution and use in source and binary forms, with or without */ |
8 | /* modification, are permitted provided that the following conditions */ |
9 | /* are met: */ |
10 | |
11 | /* 1. Redistributions of source code must retain the above copyright */ |
12 | /* notice, this list of conditions and the following disclaimer. */ |
13 | /* 2. Redistributions in binary form must reproduce the above copyright */ |
14 | /* notice, this list of conditions and the following disclaimer in the */ |
15 | /* documentation and/or other materials provided with the distribution. */ |
16 | |
17 | /* Neither the name of the University nor the names of its contributors */ |
18 | /* may be used to endorse or promote products derived from this software */ |
19 | /* without specific prior written permission. */ |
20 | |
21 | /* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR */ |
22 | /* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED */ |
23 | /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */ |
24 | /* PURPOSE. */ |
25 | |
26 | #include "flexdef.h" |
27 | static const char *check_4_gnu_m4 = |
28 | "m4_dnl ifdef(`__gnu__', ," |
29 | "`errprint(Flex requires GNU M4. Set the PATH or set the M4 environment variable to its path name.)" |
30 | " m4exit(2)')\n"; |
31 | |
32 | |
33 | /** global chain. */ |
34 | struct filter *output_chain = NULL((void *)0); |
35 | |
36 | /* Allocate and initialize an external filter. |
37 | * @param chain the current chain or NULL for new chain |
38 | * @param cmd the command to execute. |
39 | * @param ... a NULL terminated list of (const char*) arguments to command, |
40 | * not including argv[0]. |
41 | * @return newest filter in chain |
42 | */ |
43 | struct filter * |
44 | filter_create_ext(struct filter * chain, const char *cmd, |
45 | ...) |
46 | { |
47 | struct filter *f; |
48 | int max_args; |
49 | const char *s; |
50 | va_list ap; |
51 | |
52 | /* allocate and initialize new filter */ |
53 | f = calloc(sizeof(struct filter), 1); |
54 | if (!f) |
55 | flexerror(_("calloc failed (f) in filter_create_ext")"calloc failed (f) in filter_create_ext"); |
56 | f->filter_func = NULL((void *)0); |
57 | f->extra = NULL((void *)0); |
58 | f->next = NULL((void *)0); |
59 | f->argc = 0; |
60 | |
61 | if (chain != NULL((void *)0)) { |
62 | /* append f to end of chain */ |
63 | while (chain->next) |
64 | chain = chain->next; |
65 | chain->next = f; |
66 | } |
67 | /* allocate argv, and populate it with the argument list. */ |
68 | max_args = 8; |
69 | f->argv = malloc(sizeof(char *) * (max_args + 1)); |
70 | if (!f->argv) |
71 | flexerror(_("malloc failed (f->argv) in filter_create_ext")"malloc failed (f->argv) in filter_create_ext"); |
72 | f->argv[f->argc++] = cmd; |
73 | |
74 | va_start(ap, cmd)__builtin_va_start(ap, cmd); |
75 | while ((s = va_arg(ap, const char *)__builtin_va_arg(ap, const char *)) != NULL((void *)0)) { |
76 | if (f->argc >= max_args) { |
77 | max_args += 8; |
78 | f->argv = realloc(f->argv, |
79 | sizeof(char *) * (max_args + 1)); |
80 | } |
81 | f->argv[f->argc++] = s; |
82 | } |
83 | f->argv[f->argc] = NULL((void *)0); |
84 | |
85 | va_end(ap)__builtin_va_end(ap); |
86 | return f; |
87 | } |
88 | |
89 | /* Allocate and initialize an internal filter. |
90 | * @param chain the current chain or NULL for new chain |
91 | * @param filter_func The function that will perform the filtering. |
92 | * filter_func should return 0 if successful, and -1 |
93 | * if an error occurs -- or it can simply exit(). |
94 | * @param extra optional user-defined data to pass to the filter. |
95 | * @return newest filter in chain |
96 | */ |
97 | struct filter * |
98 | filter_create_int(struct filter * chain, |
99 | int (*filter_func) (struct filter *), |
100 | void *extra) |
101 | { |
102 | struct filter *f; |
103 | |
104 | /* allocate and initialize new filter */ |
105 | f = calloc(sizeof(struct filter), 1); |
106 | if (!f) |
107 | flexerror(_("calloc failed in filter_create_int")"calloc failed in filter_create_int"); |
108 | f->next = NULL((void *)0); |
109 | f->argc = 0; |
110 | f->argv = NULL((void *)0); |
111 | |
112 | f->filter_func = filter_func; |
113 | f->extra = extra; |
114 | |
115 | if (chain != NULL((void *)0)) { |
116 | /* append f to end of chain */ |
117 | while (chain->next) |
118 | chain = chain->next; |
119 | chain->next = f; |
120 | } |
121 | return f; |
122 | } |
123 | |
124 | /** Fork and exec entire filter chain. |
125 | * @param chain The head of the chain. |
126 | * @return true on success. |
127 | */ |
128 | bool_Bool |
129 | filter_apply_chain(struct filter * chain) |
130 | { |
131 | int pid, pipes[2]; |
132 | |
133 | /* |
134 | * Tricky recursion, since we want to begin the chain at the END. |
135 | * Why? Because we need all the forked processes to be children of |
136 | * the main flex process. |
137 | */ |
138 | if (chain) |
139 | filter_apply_chain(chain->next); |
140 | else |
141 | return true1; |
142 | |
143 | /* |
144 | * Now we are the right-most unprocessed link in the chain. |
145 | */ |
146 | |
147 | fflush(stdout(&__sF[1])); |
148 | fflush(stderr(&__sF[2])); |
149 | |
150 | |
151 | if (pipe(pipes) == -1) |
152 | flexerror(_("pipe failed")"pipe failed"); |
153 | |
154 | if ((pid = fork()) == -1) |
155 | flexerror(_("fork failed")"fork failed"); |
156 | |
157 | if (pid == 0) { |
158 | /* child */ |
159 | |
160 | /* |
161 | * We need stdin (the FILE* stdin) to connect to this new |
162 | * pipe. There is no portable way to set stdin to a new file |
163 | * descriptor, as stdin is not an lvalue on some systems |
164 | * (BSD). So we dup the new pipe onto the stdin descriptor |
165 | * and use a no-op fseek to sync the stream. This is a Hail |
166 | * Mary situation. It seems to work. |
167 | */ |
168 | close(pipes[1]); |
169 | clearerr(stdin)(!__isthreaded ? ((void)(((&__sF[0]))->_flags &= ~ (0x0040|0x0020))) : (clearerr)((&__sF[0]))); |
170 | if (dup2(pipes[0], fileno(stdin)(!__isthreaded ? (((&__sF[0]))->_file) : (fileno)((& __sF[0])))) == -1) |
171 | flexfatal(_("dup2(pipes[0],0)")"dup2(pipes[0],0)"); |
172 | close(pipes[0]); |
173 | fseek(stdin(&__sF[0]), 0, SEEK_CUR1); |
174 | |
175 | /* run as a filter, either internally or by exec */ |
176 | if (chain->filter_func) { |
177 | if (chain->filter_func(chain) == -1) |
178 | flexfatal(_("filter_func failed")"filter_func failed"); |
179 | exit(0); |
180 | } else { |
181 | execvp(chain->argv[0], |
182 | (char **const) (chain->argv)); |
183 | lerrsf_fatal(_("exec of %s failed")"exec of %s failed", |
184 | chain->argv[0]); |
185 | } |
186 | |
187 | exit(1); |
188 | } |
189 | /* Parent */ |
190 | close(pipes[0]); |
191 | if (dup2(pipes[1], fileno(stdout)(!__isthreaded ? (((&__sF[1]))->_file) : (fileno)((& __sF[1])))) == -1) |
192 | flexfatal(_("dup2(pipes[1],1)")"dup2(pipes[1],1)"); |
193 | close(pipes[1]); |
194 | fseek(stdout(&__sF[1]), 0, SEEK_CUR1); |
195 | |
196 | return true1; |
197 | } |
198 | |
199 | /** Truncate the chain to max_len number of filters. |
200 | * @param chain the current chain. |
201 | * @param max_len the maximum length of the chain. |
202 | * @return the resulting length of the chain. |
203 | */ |
204 | int |
205 | filter_truncate(struct filter * chain, int max_len) |
206 | { |
207 | int len = 1; |
208 | |
209 | if (!chain) |
210 | return 0; |
211 | |
212 | while (chain->next && len < max_len) { |
213 | chain = chain->next; |
214 | ++len; |
215 | } |
216 | |
217 | chain->next = NULL((void *)0); |
218 | return len; |
219 | } |
220 | |
221 | /** Splits the chain in order to write to a header file. |
222 | * Similar in spirit to the 'tee' program. |
223 | * The header file name is in extra. |
224 | * @return 0 (zero) on success, and -1 on failure. |
225 | */ |
226 | int |
227 | filter_tee_header(struct filter * chain) |
228 | { |
229 | /* |
230 | * This function reads from stdin and writes to both the C file and |
231 | * the header file at the same time. |
232 | */ |
233 | |
234 | const int readsz = 512; |
235 | char *buf; |
236 | int to_cfd = -1; |
237 | FILE *to_c = NULL((void *)0), *to_h = NULL((void *)0); |
238 | bool_Bool write_header; |
239 | |
240 | write_header = (chain->extra != NULL((void *)0)); |
241 | |
242 | /* |
243 | * Store a copy of the stdout pipe, which is already piped to C file |
244 | * through the running chain. Then create a new pipe to the H file as |
245 | * stdout, and fork the rest of the chain again. |
246 | */ |
247 | |
248 | if ((to_cfd = dup(1)) == -1) |
249 | flexfatal(_("dup(1) failed")"dup(1) failed"); |
250 | to_c = fdopen(to_cfd, "w"); |
251 | |
252 | if (write_header) { |
253 | if (freopen((char *) chain->extra, "w", stdout(&__sF[1])) == NULL((void *)0)) |
254 | flexfatal(_("freopen(headerfilename) failed")"freopen(headerfilename) failed"); |
255 | |
256 | filter_apply_chain(chain->next); |
257 | to_h = stdout(&__sF[1]); |
258 | } |
259 | /* |
260 | * Now to_c is a pipe to the C branch, and to_h is a pipe to the H |
261 | * branch. |
262 | */ |
263 | |
264 | if (write_header) { |
265 | fputs(check_4_gnu_m4, to_h); |
266 | fputs("m4_changecom`'m4_dnl\n", to_h); |
267 | fputs("m4_changequote`'m4_dnl\n", to_h); |
268 | fputs("m4_changequote([[,]])[[]]m4_dnl\n", to_h); |
269 | fputs("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", to_h); |
270 | fputs("m4_define( [[M4_YY_IN_HEADER]],[[]])m4_dnl\n", |
271 | to_h); |
272 | fprintf(to_h, "#ifndef %sHEADER_H\n", prefix); |
273 | fprintf(to_h, "#define %sHEADER_H 1\n", prefix); |
274 | fprintf(to_h, "#define %sIN_HEADER 1\n\n", prefix); |
275 | fprintf(to_h, |
276 | "m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n", |
277 | headerfilename ? headerfilename : "<stdout>"); |
278 | |
279 | } |
280 | fputs(check_4_gnu_m4, to_c); |
281 | fputs("m4_changecom`'m4_dnl\n", to_c); |
282 | fputs("m4_changequote`'m4_dnl\n", to_c); |
283 | fputs("m4_changequote([[,]])[[]]m4_dnl\n", to_c); |
284 | fputs("m4_define([[M4_YY_NOOP]])[[]]m4_dnl\n", to_c); |
285 | fprintf(to_c, "m4_define( [[M4_YY_OUTFILE_NAME]],[[%s]])m4_dnl\n", |
286 | outfilename ? outfilename : "<stdout>"); |
287 | |
288 | buf = malloc(readsz); |
289 | if (!buf) |
290 | flexerror(_("malloc failed in filter_tee_header")"malloc failed in filter_tee_header"); |
291 | while (fgets(buf, readsz, stdin(&__sF[0]))) { |
292 | fputs(buf, to_c); |
293 | if (write_header) |
294 | fputs(buf, to_h); |
295 | } |
296 | |
297 | if (write_header) { |
298 | fprintf(to_h, "\n"); |
299 | |
300 | /* |
301 | * write a fake line number. It will get fixed by the linedir |
302 | * filter. |
303 | */ |
304 | fprintf(to_h, "#line 4000 \"M4_YY_OUTFILE_NAME\"\n"); |
305 | |
306 | fprintf(to_h, "#undef %sIN_HEADER\n", prefix); |
307 | fprintf(to_h, "#endif /* %sHEADER_H */\n", prefix); |
308 | fputs("m4_undefine( [[M4_YY_IN_HEADER]])m4_dnl\n", to_h); |
309 | |
310 | fflush(to_h); |
311 | if (ferror(to_h)(!__isthreaded ? (((to_h)->_flags & 0x0040) != 0) : (ferror )(to_h))) |
312 | lerrsf(_("error writing output file %s")"error writing output file %s", |
313 | (char *) chain->extra); |
314 | |
315 | else if (fclose(to_h)) |
316 | lerrsf(_("error closing output file %s")"error closing output file %s", |
317 | (char *) chain->extra); |
318 | } |
319 | fflush(to_c); |
320 | if (ferror(to_c)(!__isthreaded ? (((to_c)->_flags & 0x0040) != 0) : (ferror )(to_c))) |
321 | lerrsf(_("error writing output file %s")"error writing output file %s", |
322 | outfilename ? outfilename : "<stdout>"); |
323 | |
324 | else if (fclose(to_c)) |
325 | lerrsf(_("error closing output file %s")"error closing output file %s", |
326 | outfilename ? outfilename : "<stdout>"); |
327 | |
328 | while (wait(0) > 0); |
329 | |
330 | exit(0); |
331 | return 0; |
332 | } |
333 | |
334 | /** Adjust the line numbers in the #line directives of the generated scanner. |
335 | * After the m4 expansion, the line numbers are incorrect since the m4 macros |
336 | * can add or remove lines. This only adjusts line numbers for generated code, |
337 | * not user code. This also happens to be a good place to squeeze multiple |
338 | * blank lines into a single blank line. |
339 | */ |
340 | int |
341 | filter_fix_linedirs(struct filter * chain) |
342 | { |
343 | char *buf; |
344 | const int readsz = 512; |
345 | int lineno = 1; |
346 | bool_Bool in_gen = true1; /* in generated code */ |
347 | bool_Bool last_was_blank = false0; |
348 | |
349 | if (!chain) |
350 | return 0; |
351 | |
352 | buf = malloc(readsz); |
353 | if (!buf) |
354 | flexerror(_("malloc failed in filter_fix_linedirs")"malloc failed in filter_fix_linedirs"); |
355 | |
356 | while (fgets(buf, readsz, stdin(&__sF[0]))) { |
357 | |
358 | regmatch_t m[10]; |
359 | |
360 | /* Check for #line directive. */ |
361 | if (buf[0] == '#' |
362 | && regexec(®ex_linedir, buf, 3, m, 0) == 0) { |
363 | |
364 | int num; |
365 | char *fname; |
366 | |
367 | /* extract the line number and filename */ |
368 | num = regmatch_strtol(&m[1], buf, NULL((void *)0), 0); |
Value stored to 'num' is never read | |
369 | fname = regmatch_dup(&m[2], buf); |
370 | |
371 | if (strcmp(fname, |
372 | outfilename ? outfilename : "<stdout>") == 0 || |
373 | strcmp(fname, headerfilename ? headerfilename : |
374 | "<stdout>") == 0) { |
375 | |
376 | char *s1, *s2; |
377 | char filename[MAXLINE2048]; |
378 | |
379 | s1 = fname; |
380 | s2 = filename; |
381 | |
382 | while ((s2 - filename) < (MAXLINE2048 - 1) && *s1) { |
383 | /* Escape the backslash */ |
384 | if (*s1 == '\\') |
385 | *s2++ = '\\'; |
386 | /* Escape the double quote */ |
387 | if (*s1 == '\"') |
388 | *s2++ = '\\'; |
389 | /* Copy the character as usual */ |
390 | *s2++ = *s1++; |
391 | } |
392 | |
393 | *s2 = '\0'; |
394 | |
395 | /* Adjust the line directives. */ |
396 | in_gen = true1; |
397 | snprintf(buf, readsz, "#line %d \"%s\"\n", |
398 | lineno + 1, filename); |
399 | } else { |
400 | /* |
401 | * it's a #line directive for code we didn't |
402 | * write |
403 | */ |
404 | in_gen = false0; |
405 | } |
406 | |
407 | free(fname); |
408 | last_was_blank = false0; |
409 | } |
410 | /* squeeze blank lines from generated code */ |
411 | else if (in_gen && |
412 | regexec(®ex_blank_line, buf, 0, NULL((void *)0), 0) == 0) { |
413 | if (last_was_blank) |
414 | continue; |
415 | else |
416 | last_was_blank = true1; |
417 | } else { |
418 | /* it's a line of normal, non-empty code. */ |
419 | last_was_blank = false0; |
420 | } |
421 | |
422 | fputs(buf, stdout(&__sF[1])); |
423 | lineno++; |
424 | } |
425 | fflush(stdout(&__sF[1])); |
426 | if (ferror(stdout)(!__isthreaded ? ((((&__sF[1]))->_flags & 0x0040) != 0) : (ferror)((&__sF[1])))) |
427 | lerrsf(_("error writing output file %s")"error writing output file %s", |
428 | outfilename ? outfilename : "<stdout>"); |
429 | |
430 | else if (fclose(stdout(&__sF[1]))) |
431 | lerrsf(_("error closing output file %s")"error closing output file %s", |
432 | outfilename ? outfilename : "<stdout>"); |
433 | |
434 | return 0; |
435 | } |