| #!/bin/sh |
| |
| # Checks some of the GNU style formatting rules in a set of patches. |
| # Copyright (C) 2010, 2012, 2016 Free Software Foundation, Inc. |
| # Contributed by Sebastian Pop <sebastian.pop@amd.com> |
| |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 3 of the License, or |
| # (at your option) any later version. |
| |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| |
| # You should have received a copy of the GNU General Public License |
| # along with this program; if not, see the file COPYING3. If not, |
| # see <http://www.gnu.org/licenses/>. |
| |
| # Set to empty in the environment to override. |
| : ${color:---color=always} |
| |
| usage() { |
| cat <<EOF |
| check_GNU_style.sh [patch]... |
| |
| Checks the patches for some of the GNU style formatting problems. |
| When FILE is -, read standard input. |
| |
| Please note that these checks are not always accurate, and |
| complete. The reference documentation of the GNU Coding Standards |
| can be found here: http://www.gnu.org/prep/standards_toc.html |
| and there are also some additional coding conventions for GCC: |
| http://gcc.gnu.org/codingconventions.html |
| |
| EOF |
| exit 1 |
| } |
| |
| test $# -eq 0 && usage |
| nfiles=$# |
| files="$*" |
| |
| stdin=false |
| stdin_tmp="" |
| if [ $nfiles -eq 1 ] && [ "$files" = "-" ]; then |
| stdin=true |
| |
| # By putting stdin into a temp file, we can handle it just like any other |
| # file. F.i., we can cat it twice, which we can't do with stdin. |
| stdin_tmp=check_GNU_style.stdin |
| cat - > $stdin_tmp |
| files=$stdin_tmp |
| else |
| for f in $files; do |
| if [ "$f" = "-" ]; then |
| # Let's keep things simple. Either we read from stdin, or we read |
| # from files specified on the command line, not both. |
| usage |
| fi |
| if [ ! -f "$f" ]; then |
| echo "error: could not read file: $f" |
| exit 1 |
| fi |
| done |
| fi |
| |
| inp=check_GNU_style.inp |
| tmp=check_GNU_style.tmp |
| tmp2=check_GNU_style.2.tmp |
| tmp3=check_GNU_style.3.tmp |
| |
| # Remove $tmp on exit and various signals. |
| trap "rm -f $inp $tmp $tmp2 $tmp3 $stdin_tmp" 0 |
| trap "rm -f $inp $tmp $tmp2 $tmp3 $stdin_tmp; exit 1" 1 2 3 5 9 13 15 |
| |
| if [ $nfiles -eq 1 ]; then |
| # There's no need for the file prefix if we're dealing only with one file. |
| format="-n" |
| else |
| format="-nH" |
| fi |
| |
| # Remove the testsuite part of the diff. We don't care about GNU style |
| # in testcases and the dg-* directives give too many false positives. |
| remove_testsuite () |
| { |
| awk 'BEGIN{testsuite=0} /^(.*:)?([1-9][0-9]*:)?\+\+\+ / && ! /testsuite\//{testsuite=0} \ |
| {if (!testsuite) print} /^(.*:)?([1-9][0-9]*:)?\+\+\+ (.*\/)?testsuite\//{testsuite=1}' |
| } |
| |
| grep $format '^+' $files \ |
| | remove_testsuite \ |
| | grep -v ':+++' \ |
| > $inp |
| |
| cat_with_prefix () |
| { |
| local f="$1" |
| |
| if [ "$prefix" = "" ]; then |
| cat "$f" |
| else |
| awk "{printf \"%s%s\n\", \"$prefix\", \$0}" $f |
| fi |
| } |
| |
| # Grep |
| g (){ |
| local msg="$1" |
| local arg="$2" |
| |
| local found=false |
| cat $inp \ |
| | egrep $color -- "$arg" \ |
| > "$tmp" && found=true |
| |
| if $found; then |
| printf "\n$msg\n" |
| cat "$tmp" |
| fi |
| } |
| |
| # And Grep |
| ag (){ |
| local msg="$1" |
| local arg1="$2" |
| local arg2="$3" |
| |
| local found=false |
| cat $inp \ |
| | egrep $color -- "$arg1" \ |
| | egrep $color -- "$arg2" \ |
| > "$tmp" && found=true |
| |
| if $found; then |
| printf "\n$msg\n" |
| cat "$tmp" |
| fi |
| } |
| |
| # reVerse Grep |
| vg (){ |
| local msg="$1" |
| local varg="$2" |
| local arg="$3" |
| |
| local found=false |
| cat $inp \ |
| | egrep -v -- "$varg" \ |
| | egrep $color -- "$arg" \ |
| > "$tmp" && found=true |
| |
| if $found; then |
| printf "\n$msg\n" |
| cat "$tmp" |
| fi |
| } |
| |
| col (){ |
| local msg="$1" |
| |
| local first=true |
| local f |
| for f in $files; do |
| prefix="" |
| if [ $nfiles -ne 1 ]; then |
| prefix="$f:" |
| fi |
| |
| # Don't reuse $inp, which may be generated using -H and thus contain a |
| # file prefix. Re-remove the testsuite since we're not using $inp. |
| cat $f | remove_testsuite \ |
| | grep -n '^+' \ |
| | grep -v ':+++' \ |
| > $tmp |
| |
| # Keep only line number prefix and patch modifier '+'. |
| cat "$tmp" \ |
| | sed 's/\(^[0-9][0-9]*:+\).*/\1/' \ |
| > "$tmp2" |
| |
| # Remove line number prefix and patch modifier '+'. |
| # Expand tabs to spaces according to tab positions. |
| # Keep long lines, make short lines empty. Print the part past 80 chars |
| # in red. |
| cat "$tmp" \ |
| | sed 's/^[0-9]*:+//' \ |
| | expand \ |
| | awk '{ \ |
| if (length($0) > 80) \ |
| printf "%s\033[1;31m%s\033[0m\n", \ |
| substr($0,1,80), \ |
| substr($0,81); \ |
| else \ |
| print "" \ |
| }' \ |
| > "$tmp3" |
| |
| # Combine prefix back with long lines. |
| # Filter out empty lines. |
| local found=false |
| paste -d '\0' "$tmp2" "$tmp3" \ |
| | grep -v '^[0-9][0-9]*:+$' \ |
| > "$tmp" && found=true |
| |
| if $found; then |
| if $first; then |
| printf "\n$msg\n" |
| first=false |
| fi |
| cat_with_prefix "$tmp" |
| fi |
| done |
| } |
| |
| |
| col 'Lines should not exceed 80 characters.' |
| |
| g 'Blocks of 8 spaces should be replaced with tabs.' \ |
| ' {8}' |
| |
| g 'Trailing whitespace.' \ |
| '[[:space:]]$' |
| |
| g 'Space before dot.' \ |
| '[[:alnum:]][[:blank:]]+\.' |
| |
| g 'Dot, space, space, new sentence.' \ |
| '[[:alnum:]]\.([[:blank:]]|[[:blank:]]{3,})[A-Z0-9]' |
| |
| g 'Dot, space, space, end of comment.' \ |
| '[[:alnum:]]\.([[:blank:]]{0,1}|[[:blank:]]{3,})\*/' |
| |
| g 'Sentences should end with a dot. Dot, space, space, end of the comment.' \ |
| '[[:alnum:]][[:blank:]]*\*/' |
| |
| vg 'There should be exactly one space between function name and parenthesis.' \ |
| '\#define' \ |
| '[[:alnum:]]([[:blank:]]{2,})?\(' |
| |
| g 'There should be no space before a left square bracket.' \ |
| '[[:alnum:]][[:blank:]]+\[' |
| |
| g 'There should be no space before closing parenthesis.' \ |
| '[[:graph:]][[:blank:]]+\)' |
| |
| # This will give false positives for C99 compound literals. |
| g 'Braces should be on a separate line.' \ |
| '(\)|else)[[:blank:]]*{' |
| |
| # Does this apply to definitions of aggregate objects? |
| ag 'Trailing operator.' \ |
| '^[1-9][0-9]*:\+[[:space:]]' \ |
| '(([^a-zA-Z_]\*)|([-%<=&|^?])|([^*]/)|([^:][+]))$' |