2 # Filter C code so that CPP #-directives are indented to reflect nesting.
3 # written by Jim Meyering
5 # This code is included here solely to provide a little perspective
6 # on the development process and evolution of the package. The Lex/C
7 # version is much more efficient.
12 if (@ARGV && $ARGV[0] eq '-c')
17 unshift (@ARGV, '-') if @ARGV == 0;
19 die "usage: $0 [FILE]\n" if @ARGV > 1;
21 my $file = shift @ARGV;
22 my $exit_status = cpp_indent
($file, $checking);
26 # ===============================
28 # Return 2 for syntax problems.
29 # Return 1 for invalid indentation of CPP #-directives (only if $checking).
31 # return 0 if syntax and indentation are valid
33 # if (syntax is valid)
35 # print properly indented code to stdout
40 my ($file, $checking) = @_;
41 my $start_of_last_comment_or_string;
48 my ($state, $line) = @_;
50 my $new_string_or_comment = 0;
53 #warn "s: $state: line=$line";
55 if ($state == IN_CODE
)
57 my $i = index ($line, '"');
58 my $j = index ($line, '/*');
59 last if ($i < 0 && $j < 0);
61 # A double quote inside single quotes doesn't count.
62 $i = -1 if substr ($line, $i - 1, 1) eq "'";
78 $k = ($i < $j ?
$i : $j);
81 $state = ($k == $i ? IN_STRING
: IN_COMMENT
);
82 $remainder = substr ($line, $k + 1);
83 $new_string_or_comment = 1;
85 elsif ($state == IN_COMMENT
)
93 else # $state == IN_STRING
95 if ($line =~ m!\\*\"!)
97 $state = IN_CODE if (length ($&) % 2 == 1);
104 return ($state, $new_string_or_comment);
106 # ===============================================================
108 # TODO: allow this to be overridden by a command-line option.
109 my $indent_incr = ' ';
114 open (FILE
, $file) || die "$0: couldn't open $file: $!\n";
119 while (defined ($line = <FILE
>))
123 if ($state == IN_CODE
)
125 my $saved_line = $line;
126 if ($line =~ s/^\s*\#\s*//)
130 my $pfx = "$0: $file: line $.";
132 || $line =~ /^ifdef\b/
133 || $line =~ /^ifndef\b/)
135 # Maintain stack of (line number, keyword) pairs to better
136 # report any `unterminated #if...' errors.
137 push @opener_stack, {LINE_NUMBER
=> $., KEYWORD
=> $&};
139 $indent = $indent_incr x
$depth;
142 elsif ($line =~ /^(else|elif)\b/)
146 warn "$pfx: found #$& without matching #if\n";
151 $indent = $indent_incr x
($depth - 1);
153 elsif ($line =~ /^endif\b/)
157 warn "$pfx: found #$& without matching #if\n";
163 $indent = $indent_incr x
$depth;
168 # Handle #error, #include, #pragma, etc.
170 $indent = $indent_incr x
$depth;
173 if ($checking && $saved_line ne "#$indent$keyword$'")
175 warn "$pfx: not properly indented\n";
180 $line = "#$indent$keyword$'";
192 #print $state if !$checking;
193 print $line if !$checking;
196 ($state, $new_non_code) = update_state ($state, $rest);
197 $start_of_last_comment_or_string = $.
205 foreach $x (@opener_stack)
207 warn "$0: $file: line $x->{LINE_NUMBER}: "
208 . "unterminated #$x->{KEYWORD}\n";
213 if ($state != IN_CODE)
215 my $type = ($state == IN_COMMENT && 'comment
' || 'string
');
216 warn "$0: $file: line $start_of_last_comment_or_string "
217 . "unterminated $type\n";