diff --git a/.github/scripts/c-comments b/.github/scripts/c-comments new file mode 100755 index 0000000000..f8c30cf0f9 --- /dev/null +++ b/.github/scripts/c-comments @@ -0,0 +1,191 @@ +#!/usr/bin/env perl +# Copyright (C) Daniel Stenberg, , 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() { + my $l = $_; + ($state, $flags, $line) = scanline(0, $state, $flags, $l); + print "$line"; + } + close(F); +} + +for my $f (@ARGV) { + strip($f); +} diff --git a/.github/scripts/c-strip b/.github/scripts/c-strip new file mode 100755 index 0000000000..6b5cfbf863 --- /dev/null +++ b/.github/scripts/c-strip @@ -0,0 +1,7 @@ +#!/bin/sh +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +./.github/scripts/c-comments "$1" > temp +mv temp "$1" diff --git a/.github/workflows/checksrc.yml b/.github/workflows/checksrc.yml index a5d18356db..f6a2ec84e5 100644 --- a/.github/workflows/checksrc.yml +++ b/.github/workflows/checksrc.yml @@ -66,20 +66,6 @@ jobs: source ~/venv/bin/activate reuse lint - - name: 'codespell' - run: | - source ~/venv/bin/activate - codespell --version - .github/scripts/codespell.sh - - - name: 'typos' - timeout-minutes: 2 - run: | - /home/linuxbrew/.linuxbrew/bin/brew install typos-cli - eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - typos --version - .github/scripts/typos.sh - - name: 'cmakelint' run: | source ~/venv/bin/activate @@ -96,6 +82,24 @@ jobs: source ~/venv/bin/activate scripts/pythonlint.sh + - name: filter off code from all C and H files + run: | + git ls-files -z '**.[ch]' | xargs -0 -r -n1 ./.github/scripts/c-strip + + - name: 'codespell' + run: | + source ~/venv/bin/activate + codespell --version + .github/scripts/codespell.sh + + - name: 'typos' + timeout-minutes: 2 + run: | + /home/linuxbrew/.linuxbrew/bin/brew install typos-cli + eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" + typos --version + .github/scripts/typos.sh + pytype: name: 'pytype' runs-on: ubuntu-24.04-arm # pytype is discontinued and requires python 3.8-3.12