indent: allow more than 5 levels of #if/#endifdiff -r1.10 -r1.11 src/tests/usr.bin/indent/lsym_preprocessing.c
(rillig)
--- src/tests/usr.bin/indent/lsym_preprocessing.c 2023/05/13 08:33:39 1.10
+++ src/tests/usr.bin/indent/lsym_preprocessing.c 2023/06/14 10:26:00 1.11
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: lsym_preprocessing.c,v 1.10 2023/05/13 08:33:39 rillig Exp $ */ | 1 | /* $NetBSD: lsym_preprocessing.c,v 1.11 2023/06/14 10:26:00 rillig Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Tests for the token lsym_preprocessing, which represents a '#' that starts | 4 | * Tests for the token lsym_preprocessing, which represents a '#' that starts | |
5 | * a preprocessing line. | 5 | * a preprocessing line. | |
6 | * | 6 | * | |
7 | * #define | 7 | * #define | |
8 | * #ifdef | 8 | * #ifdef | |
9 | * #include | 9 | * #include | |
10 | * #line | 10 | * #line | |
11 | * #pragma | 11 | * #pragma | |
12 | * | 12 | * | |
13 | * The whole preprocessing line is processed separately from the main source | 13 | * The whole preprocessing line is processed separately from the main source | |
14 | * code, without much tokenizing or parsing. | 14 | * code, without much tokenizing or parsing. | |
@@ -246,13 +246,65 @@ int first_line; | @@ -246,13 +246,65 @@ int first_line; | |||
246 | //indent end | 246 | //indent end | |
247 | 247 | |||
248 | //indent run -di0 | 248 | //indent run -di0 | |
249 | int first_line; | 249 | int first_line; | |
250 | int before; | 250 | int before; | |
251 | #if 0 | 251 | #if 0 | |
252 | /*INDENT OFF*/ | 252 | /*INDENT OFF*/ | |
253 | int off; | 253 | int off; | |
254 | #else | 254 | #else | |
255 | int on; | 255 | int on; | |
256 | #endif | 256 | #endif | |
257 | int after; | 257 | int after; | |
258 | //indent end | 258 | //indent end | |
259 | ||||
260 | ||||
261 | /* | |||
262 | * Before 2023-06-14, indent was limited to 5 levels of conditional compilation | |||
263 | * directives. | |||
264 | */ | |||
265 | //indent input | |||
266 | #if 1 | |||
267 | #if 2 | |||
268 | #if 3 | |||
269 | #if 4 | |||
270 | #if 5 | |||
271 | #if 6 | |||
272 | #endif 6 | |||
273 | #endif 5 | |||
274 | #endif 4 | |||
275 | #endif 3 | |||
276 | #endif 2 | |||
277 | #endif 1 | |||
278 | //indent end | |||
279 | ||||
280 | //indent run-equals-input | |||
281 | ||||
282 | ||||
283 | /* | |||
284 | * Unrecognized and unmatched preprocessing directives are preserved. | |||
285 | */ | |||
286 | //indent input | |||
287 | #else | |||
288 | #elif 0 | |||
289 | #elifdef var | |||
290 | #endif | |||
291 | ||||
292 | #unknown | |||
293 | # 3 "file.c" | |||
294 | //indent end | |||
295 | ||||
296 | //indent run | |||
297 | error: Standard Input:1: Unmatched #else | |||
298 | error: Standard Input:2: Unmatched #elif | |||
299 | // $ TODO: '#elifdef' instead of '#elif' | |||
300 | error: Standard Input:3: Unmatched #elif | |||
301 | error: Standard Input:4: Unmatched #endif | |||
302 | #else | |||
303 | #elif 0 | |||
304 | #elifdef var | |||
305 | #endif | |||
306 | ||||
307 | #unknown | |||
308 | # 3 "file.c" | |||
309 | exit 1 | |||
310 | //indent end |
--- src/tests/usr.bin/indent/t_errors.sh 2023/06/10 17:35:41 1.35
+++ src/tests/usr.bin/indent/t_errors.sh 2023/06/14 10:26:00 1.36
@@ -1,15 +1,15 @@ | @@ -1,15 +1,15 @@ | |||
1 | #! /bin/sh | 1 | #! /bin/sh | |
2 | # $NetBSD: t_errors.sh,v 1.35 2023/06/10 17:35:41 rillig Exp $ | 2 | # $NetBSD: t_errors.sh,v 1.36 2023/06/14 10:26:00 rillig Exp $ | |
3 | # | 3 | # | |
4 | # Copyright (c) 2021 The NetBSD Foundation, Inc. | 4 | # Copyright (c) 2021 The NetBSD Foundation, Inc. | |
5 | # All rights reserved. | 5 | # All rights reserved. | |
6 | # | 6 | # | |
7 | # Redistribution and use in source and binary forms, with or without | 7 | # Redistribution and use in source and binary forms, with or without | |
8 | # modification, are permitted provided that the following conditions | 8 | # modification, are permitted provided that the following conditions | |
9 | # are met: | 9 | # are met: | |
10 | # 1. Redistributions of source code must retain the above copyright | 10 | # 1. Redistributions of source code must retain the above copyright | |
11 | # notice, this list of conditions and the following disclaimer. | 11 | # notice, this list of conditions and the following disclaimer. | |
12 | # 2. Redistributions in binary form must reproduce the above copyright | 12 | # 2. Redistributions in binary form must reproduce the above copyright | |
13 | # notice, this list of conditions and the following disclaimer in the | 13 | # notice, this list of conditions and the following disclaimer in the | |
14 | # documentation and/or other materials provided with the distribution. | 14 | # documentation and/or other materials provided with the distribution. | |
15 | # | 15 | # | |
@@ -338,74 +338,26 @@ unexpected_closing_brace_decl_body() | @@ -338,74 +338,26 @@ unexpected_closing_brace_decl_body() | |||
338 | { | 338 | { | |
339 | echo 'int i = 3};' > code.c | 339 | echo 'int i = 3};' > code.c | |
340 | 340 | |||
341 | expect_error \ | 341 | expect_error \ | |
342 | 'error: code.c:1: Statement nesting error' \ | 342 | 'error: code.c:1: Statement nesting error' \ | |
343 | code.c | 343 | code.c | |
344 | # Despite the error message, the original file got overwritten with a | 344 | # Despite the error message, the original file got overwritten with a | |
345 | # best-effort rewrite of the code. | 345 | # best-effort rewrite of the code. | |
346 | atf_check \ | 346 | atf_check \ | |
347 | -o 'inline:int i = 3};\n' \ | 347 | -o 'inline:int i = 3};\n' \ | |
348 | cat code.c | 348 | cat code.c | |
349 | } | 349 | } | |
350 | 350 | |||
351 | atf_test_case 'preprocessing_overflow' | |||
352 | preprocessing_overflow_body() | |||
353 | { | |||
354 | cat <<-\EOF > code.c | |||
355 | #if 1 | |||
356 | #if 2 | |||
357 | #if 3 | |||
358 | #if 4 | |||
359 | #if 5 | |||
360 | #if 6 | |||
361 | #endif 6 | |||
362 | #endif 5 | |||
363 | #endif 4 | |||
364 | #endif 3 | |||
365 | #endif 2 | |||
366 | #endif 1 | |||
367 | #endif too much | |||
368 | EOF | |||
369 | cat <<-\EOF > stderr.exp | |||
370 | error: code.c:6: #if stack overflow | |||
371 | error: code.c:12: Unmatched #endif | |||
372 | error: code.c:13: Unmatched #endif | |||
373 | EOF | |||
374 | ||||
375 | atf_check -s 'exit:1' \ | |||
376 | -e 'file:stderr.exp' \ | |||
377 | "$indent" code.c | |||
378 | } | |||
379 | ||||
380 | atf_test_case 'preprocessing_unrecognized' | |||
381 | preprocessing_unrecognized_body() | |||
382 | { | |||
383 | cat <<-\EOF > code.c | |||
384 | #unknown | |||
385 | # 3 "file.c" | |||
386 | #elif 3 | |||
387 | #else | |||
388 | EOF | |||
389 | cat <<-\EOF > stderr.exp | |||
390 | error: code.c:3: Unmatched #elif | |||
391 | error: code.c:4: Unmatched #else | |||
392 | EOF | |||
393 | ||||
394 | atf_check -s 'exit:1' \ | |||
395 | -e 'file:stderr.exp' \ | |||
396 | "$indent" code.c | |||
397 | } | |||
398 | ||||
399 | atf_test_case 'unbalanced_parentheses' | 351 | atf_test_case 'unbalanced_parentheses' | |
400 | unbalanced_parentheses_body() | 352 | unbalanced_parentheses_body() | |
401 | { | 353 | { | |
402 | cat <<-\EOF > code.c | 354 | cat <<-\EOF > code.c | |
403 | int var = | 355 | int var = | |
404 | ( | 356 | ( | |
405 | ; | 357 | ; | |
406 | ) | 358 | ) | |
407 | ; | 359 | ; | |
408 | EOF | 360 | EOF | |
409 | cat <<-\EOF > stderr.exp | 361 | cat <<-\EOF > stderr.exp | |
410 | error: code.c:3: Unbalanced parentheses | 362 | error: code.c:3: Unbalanced parentheses | |
411 | warning: code.c:4: Extra ')' | 363 | warning: code.c:4: Extra ')' | |
@@ -534,21 +486,19 @@ atf_init_test_cases() | @@ -534,21 +486,19 @@ atf_init_test_cases() | |||
534 | atf_add_test_case 'unterminated_comment_wrap' | 486 | atf_add_test_case 'unterminated_comment_wrap' | |
535 | atf_add_test_case 'unterminated_comment_nowrap' | 487 | atf_add_test_case 'unterminated_comment_nowrap' | |
536 | atf_add_test_case 'unterminated_char_constant' | 488 | atf_add_test_case 'unterminated_char_constant' | |
537 | atf_add_test_case 'unterminated_string_literal' | 489 | atf_add_test_case 'unterminated_string_literal' | |
538 | atf_add_test_case 'in_place_wrong_backup' | 490 | atf_add_test_case 'in_place_wrong_backup' | |
539 | atf_add_test_case 'argument_input_enoent' | 491 | atf_add_test_case 'argument_input_enoent' | |
540 | atf_add_test_case 'argument_output_equals_input_name' | 492 | atf_add_test_case 'argument_output_equals_input_name' | |
541 | atf_add_test_case 'argument_output_equals_input_file' | 493 | atf_add_test_case 'argument_output_equals_input_file' | |
542 | atf_add_test_case 'argument_output_enoent' | 494 | atf_add_test_case 'argument_output_enoent' | |
543 | atf_add_test_case 'argument_too_many' | 495 | atf_add_test_case 'argument_too_many' | |
544 | atf_add_test_case 'unexpected_end_of_file' | 496 | atf_add_test_case 'unexpected_end_of_file' | |
545 | atf_add_test_case 'unexpected_closing_brace_top_level' | 497 | atf_add_test_case 'unexpected_closing_brace_top_level' | |
546 | atf_add_test_case 'unexpected_closing_brace_decl' | 498 | atf_add_test_case 'unexpected_closing_brace_decl' | |
547 | atf_add_test_case 'preprocessing_overflow' | |||
548 | atf_add_test_case 'preprocessing_unrecognized' | |||
549 | atf_add_test_case 'unbalanced_parentheses' | 499 | atf_add_test_case 'unbalanced_parentheses' | |
550 | atf_add_test_case 'gcc_statement_expression' | 500 | atf_add_test_case 'gcc_statement_expression' | |
551 | atf_add_test_case 'crash_comment_after_controlling_expression' | 501 | atf_add_test_case 'crash_comment_after_controlling_expression' | |
552 | atf_add_test_case 'comment_fits_in_one_line' | 502 | atf_add_test_case 'comment_fits_in_one_line' | |
553 | atf_add_test_case 'stack_overflow' | 503 | atf_add_test_case 'stack_overflow' | |
554 | } | 504 | } |
--- src/usr.bin/indent/indent.c 2023/06/14 08:36:51 1.359
+++ src/usr.bin/indent/indent.c 2023/06/14 10:26:00 1.360
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: indent.c,v 1.359 2023/06/14 08:36:51 rillig Exp $ */ | 1 | /* $NetBSD: indent.c,v 1.360 2023/06/14 10:26:00 rillig Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * SPDX-License-Identifier: BSD-4-Clause | 4 | * SPDX-License-Identifier: BSD-4-Clause | |
5 | * | 5 | * | |
6 | * Copyright (c) 1985 Sun Microsystems, Inc. | 6 | * Copyright (c) 1985 Sun Microsystems, Inc. | |
7 | * Copyright (c) 1976 Board of Trustees of the University of Illinois. | 7 | * Copyright (c) 1976 Board of Trustees of the University of Illinois. | |
8 | * Copyright (c) 1980, 1993 | 8 | * Copyright (c) 1980, 1993 | |
9 | * The Regents of the University of California. All rights reserved. | 9 | * The Regents of the University of California. All rights reserved. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
@@ -28,27 +28,27 @@ | @@ -28,27 +28,27 @@ | |||
28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
37 | * SUCH DAMAGE. | 37 | * SUCH DAMAGE. | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | #include <sys/cdefs.h> | 40 | #include <sys/cdefs.h> | |
41 | __RCSID("$NetBSD: indent.c,v 1.359 2023/06/14 08:36:51 rillig Exp $"); | 41 | __RCSID("$NetBSD: indent.c,v 1.360 2023/06/14 10:26:00 rillig Exp $"); | |
42 | 42 | |||
43 | #include <sys/param.h> | 43 | #include <sys/param.h> | |
44 | #include <err.h> | 44 | #include <err.h> | |
45 | #include <stdarg.h> | 45 | #include <stdarg.h> | |
46 | #include <stdio.h> | 46 | #include <stdio.h> | |
47 | #include <stdlib.h> | 47 | #include <stdlib.h> | |
48 | #include <string.h> | 48 | #include <string.h> | |
49 | 49 | |||
50 | #include "indent.h" | 50 | #include "indent.h" | |
51 | 51 | |||
52 | struct options opt = { | 52 | struct options opt = { | |
53 | .brace_same_line = true, | 53 | .brace_same_line = true, | |
54 | .comment_delimiter_on_blank_line = true, | 54 | .comment_delimiter_on_blank_line = true, | |
@@ -72,28 +72,31 @@ struct options opt = { | @@ -72,28 +72,31 @@ struct options opt = { | |||
72 | 72 | |||
73 | struct parser_state ps; | 73 | struct parser_state ps; | |
74 | 74 | |||
75 | struct buffer token; | 75 | struct buffer token; | |
76 | 76 | |||
77 | struct buffer lab; | 77 | struct buffer lab; | |
78 | struct buffer code; | 78 | struct buffer code; | |
79 | struct buffer com; | 79 | struct buffer com; | |
80 | 80 | |||
81 | bool found_err; | 81 | bool found_err; | |
82 | bool had_eof; | 82 | bool had_eof; | |
83 | int line_no = 1; | 83 | int line_no = 1; | |
84 | 84 | |||
85 | static int ifdef_level; | 85 | static struct { | |
86 | static struct parser_state state_stack[5]; | 86 | struct parser_state *item; | |
87 | size_t len; | |||
88 | size_t cap; | |||
89 | } ifdef; | |||
87 | 90 | |||
88 | FILE *input; | 91 | FILE *input; | |
89 | FILE *output; | 92 | FILE *output; | |
90 | 93 | |||
91 | static const char *in_name = "Standard Input"; | 94 | static const char *in_name = "Standard Input"; | |
92 | static char backup_name[PATH_MAX]; | 95 | static char backup_name[PATH_MAX]; | |
93 | static const char *backup_suffix = ".BAK"; | 96 | static const char *backup_suffix = ".BAK"; | |
94 | 97 | |||
95 | 98 | |||
96 | void * | 99 | void * | |
97 | nonnull(void *p) | 100 | nonnull(void *p) | |
98 | { | 101 | { | |
99 | if (p == NULL) | 102 | if (p == NULL) | |
@@ -446,44 +449,46 @@ process_preprocessing(void) | @@ -446,44 +449,46 @@ process_preprocessing(void) | |||
446 | if (lab.len > 0 || code.len > 0 || com.len > 0) | 449 | if (lab.len > 0 || code.len > 0 || com.len > 0) | |
447 | output_line(); | 450 | output_line(); | |
448 | 451 | |||
449 | read_preprocessing_line(); | 452 | read_preprocessing_line(); | |
450 | 453 | |||
451 | const char *dir = lab.s + 1, *line_end = lab.s + lab.len; | 454 | const char *dir = lab.s + 1, *line_end = lab.s + lab.len; | |
452 | while (dir < line_end && ch_isblank(*dir)) | 455 | while (dir < line_end && ch_isblank(*dir)) | |
453 | dir++; | 456 | dir++; | |
454 | size_t dir_len = 0; | 457 | size_t dir_len = 0; | |
455 | while (dir + dir_len < line_end && ch_isalpha(dir[dir_len])) | 458 | while (dir + dir_len < line_end && ch_isalpha(dir[dir_len])) | |
456 | dir_len++; | 459 | dir_len++; | |
457 | 460 | |||
458 | if (dir_len >= 2 && memcmp(dir, "if", 2) == 0) { | 461 | if (dir_len >= 2 && memcmp(dir, "if", 2) == 0) { | |
459 | if ((size_t)ifdef_level < array_length(state_stack)) | 462 | if (ifdef.len >= ifdef.cap) { | |
460 | state_stack[ifdef_level++] = ps; | 463 | ifdef.cap += 5; | |
461 | else | 464 | ifdef.item = nonnull(realloc(ifdef.item, | |
462 | diag(1, "#if stack overflow"); | 465 | sizeof(ifdef.item[0]) * ifdef.cap)); | |
466 | } | |||
467 | ifdef.item[ifdef.len++] = ps; | |||
463 | out.line_kind = lk_if; | 468 | out.line_kind = lk_if; | |
464 | 469 | |||
465 | } else if (dir_len >= 2 && memcmp(dir, "el", 2) == 0) { | 470 | } else if (dir_len >= 2 && memcmp(dir, "el", 2) == 0) { | |
466 | if (ifdef_level <= 0) | 471 | if (ifdef.len == 0) | |
467 | diag(1, dir[2] == 'i' | 472 | diag(1, dir[2] == 'i' | |
468 | ? "Unmatched #elif" : "Unmatched #else"); | 473 | ? "Unmatched #elif" : "Unmatched #else"); | |
469 | else | 474 | else | |
470 | ps = state_stack[ifdef_level - 1]; | 475 | ps = ifdef.item[ifdef.len - 1]; | |
471 | 476 | |||
472 | } else if (dir_len == 5 && memcmp(dir, "endif", 5) == 0) { | 477 | } else if (dir_len == 5 && memcmp(dir, "endif", 5) == 0) { | |
473 | if (ifdef_level <= 0) | 478 | if (ifdef.len == 0) | |
474 | diag(1, "Unmatched #endif"); | 479 | diag(1, "Unmatched #endif"); | |
475 | else | 480 | else | |
476 | ifdef_level--; | 481 | ifdef.len--; | |
477 | out.line_kind = lk_endif; | 482 | out.line_kind = lk_endif; | |
478 | } | 483 | } | |
479 | } | 484 | } | |
480 | 485 | |||
481 | static void | 486 | static void | |
482 | process_newline(void) | 487 | process_newline(void) | |
483 | { | 488 | { | |
484 | if (ps.prev_lsym == lsym_comma | 489 | if (ps.prev_lsym == lsym_comma | |
485 | && ps.nparen == 0 && !ps.in_init | 490 | && ps.nparen == 0 && !ps.in_init | |
486 | && !opt.break_after_comma && ps.break_after_comma | 491 | && !opt.break_after_comma && ps.break_after_comma | |
487 | && lab.len == 0 /* for preprocessing lines */ | 492 | && lab.len == 0 /* for preprocessing lines */ | |
488 | && com.len == 0) | 493 | && com.len == 0) | |
489 | goto stay_in_line; | 494 | goto stay_in_line; |