| #!/usr/bin/env perl |
| # Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
| # |
| # SPDX-License-Identifier: curl |
| |
| # Output all the C comments and double-quoted strings in the given source |
| # files. All other contents should be blanked out. Output the text at the same |
| # horizontal position as in the original file. |
| # |
| # Ignores strings for the preprocessor. |
| # |
| ## States |
| # |
| # 0 - default, initial state |
| # 1 - there was a slash |
| # 2 - quoted string |
| # 3 - // comment |
| # 4 - /* comment |
| # 5 - asterisk found within a /* comment |
| # 6 - #include line |
| # 7 - backslash in a string |
| # 8 - backslash in plain code |
| # 9 - single quote in plain code |
| # |
| ## Flags |
| # |
| # 1 - include preprocessor line, ignore strings |
| |
| sub scanline { |
| my ($col, $state, $flags, $l) = @_; |
| my $line; |
| |
| if($state == 3) { |
| # // ended on the prev line, go back to init |
| $state = 0; |
| } |
| |
| if(($state == 0) && ($l =~ /^ *\# *include/)) { |
| # preprocessor include line |
| $flags |= 1; |
| } |
| else { |
| # not preprocessor |
| $flags &= ~1; |
| } |
| |
| my @c = split(//, $l); |
| |
| # state machine this line |
| for my $c (@c) { |
| if($state == 1) { |
| # we had a slash |
| if($c eq "/") { |
| # // confirmed, the rest of the line is a comment |
| $line .= "//"; |
| $state = 3; |
| } |
| elsif($c eq "*") { |
| # /* confirmed |
| $state = 4; |
| $line .= "/*"; |
| } |
| else { |
| # back to normal |
| $line .= " "; |
| $state = 0; |
| } |
| } |
| elsif($state == 2) { |
| # a string |
| if($c eq "\\") { |
| $line .= "\\"; |
| $state = 7; |
| } |
| elsif($c eq "\"") { |
| # end of the string |
| $line .= "\""; |
| $state = 0; |
| } |
| else { |
| $line .= $c; |
| } |
| } |
| elsif($state == 3) { |
| # a // comment |
| $line .= $c; |
| } |
| elsif($state == 4) { |
| # an ongoing /* comment |
| if($c eq "*") { |
| # could a comment close |
| $state = 5; |
| } |
| else { |
| $line .= $c; |
| } |
| } |
| elsif($state == 5) { |
| if($c eq "/") { |
| # a /* */ comment ended here */ |
| $line .= "*/"; |
| $state = 0; |
| } |
| else { |
| # the /* comment continues |
| $line .= "*$c"; |
| $state = 4; |
| } |
| } |
| elsif($state == 7) { |
| # the prev was a backslash in a string |
| $line .= $c; |
| # switch back to normal string |
| $state = 2; |
| } |
| elsif($state == 8) { |
| # the prev was a backslash in code |
| if($c eq "\n") { |
| $line .= $c; |
| } |
| else { |
| #$line .= " "; |
| } |
| # switch back to plain code |
| $state = 0; |
| } |
| elsif($state == 9) { |
| # the prev was a single quote in code |
| if($c eq "\n") { |
| $line .= $c; |
| # switch back to plain code |
| $state = 0; |
| } |
| elsif($c eq "\\") { |
| # a backslash followed the quote |
| $line .= " "; |
| $state = 8; |
| } |
| else { |
| # switch back to plain code |
| $state = 0; |
| } |
| } |
| else { |
| if($c eq "\\") { |
| # got a backslash |
| $line .= " "; |
| $state = 8 |
| } |
| elsif($c eq "\'") { |
| # got a single quote |
| $line .= " "; |
| $state = 9 |
| } |
| if($c eq "/") { |
| $state = 1; # got a slash |
| } |
| elsif(($c eq "\"") && !($flags & 1)) { |
| # start of a string, not within a preprocessor line |
| $line .= "\""; |
| $state = 2; |
| } |
| elsif($c eq "\n") { |
| $line .= "\n"; |
| } |
| else { |
| $line .= " "; |
| } |
| } |
| } |
| # strip trailing space |
| $line =~ s/( +)\n/\n/; |
| return $state, $flags, $line; |
| } |
| |
| sub strip { |
| my ($f) = @_; |
| my $state = 0; |
| my $flags = 0; |
| open(F, "<$f") || die "can't open $f"; |
| while(<F>) { |
| my $l = $_; |
| ($state, $flags, $line) = scanline(0, $state, $flags, $l); |
| print "$line"; |
| } |
| close(F); |
| } |
| |
| for my $f (@ARGV) { |
| strip($f); |
| } |