Wed Jun 14 10:26:00 2023 UTC ()
indent: allow more than 5 levels of #if/#endif


(rillig)
diff -r1.10 -r1.11 src/tests/usr.bin/indent/lsym_preprocessing.c
diff -r1.35 -r1.36 src/tests/usr.bin/indent/t_errors.sh
diff -r1.359 -r1.360 src/usr.bin/indent/indent.c

cvs diff -r1.10 -r1.11 src/tests/usr.bin/indent/lsym_preprocessing.c (expand / switch to unified diff)

--- 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
249int first_line; 249int first_line;
250int before; 250int 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
 297error: Standard Input:1: Unmatched #else
 298error: Standard Input:2: Unmatched #elif
 299// $ TODO: '#elifdef' instead of '#elif'
 300error: Standard Input:3: Unmatched #elif
 301error: Standard Input:4: Unmatched #endif
 302#else
 303#elif 0
 304#elifdef var
 305#endif
 306
 307#unknown
 308# 3 "file.c"
 309exit 1
 310//indent end

cvs diff -r1.35 -r1.36 src/tests/usr.bin/indent/t_errors.sh (expand / switch to unified diff)

--- 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
351atf_test_case 'preprocessing_overflow' 
352preprocessing_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 
380atf_test_case 'preprocessing_unrecognized' 
381preprocessing_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 
399atf_test_case 'unbalanced_parentheses' 351atf_test_case 'unbalanced_parentheses'
400unbalanced_parentheses_body() 352unbalanced_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}

cvs diff -r1.359 -r1.360 src/usr.bin/indent/indent.c (expand / switch to unified diff)

--- 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
52struct options opt = { 52struct 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
73struct parser_state ps; 73struct parser_state ps;
74 74
75struct buffer token; 75struct buffer token;
76 76
77struct buffer lab; 77struct buffer lab;
78struct buffer code; 78struct buffer code;
79struct buffer com; 79struct buffer com;
80 80
81bool found_err; 81bool found_err;
82bool had_eof; 82bool had_eof;
83int line_no = 1; 83int line_no = 1;
84 84
85static int ifdef_level; 85static struct {
86static struct parser_state state_stack[5]; 86 struct parser_state *item;
 87 size_t len;
 88 size_t cap;
 89} ifdef;
87 90
88FILE *input; 91FILE *input;
89FILE *output; 92FILE *output;
90 93
91static const char *in_name = "Standard Input"; 94static const char *in_name = "Standard Input";
92static char backup_name[PATH_MAX]; 95static char backup_name[PATH_MAX];
93static const char *backup_suffix = ".BAK"; 96static const char *backup_suffix = ".BAK";
94 97
95 98
96void * 99void *
97nonnull(void *p) 100nonnull(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
481static void 486static void
482process_newline(void) 487process_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;