#!/bin/sh # Checks some of the GNU style formatting rules in a set of patches. # Copyright (C) 2010-2023 Free Software Foundation, Inc. # Contributed by Sebastian Pop # 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 . # Set to empty in the environment to override. : ${color:---color=always} usage() { 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_]\*)|([-%<=&|^?])|([^*]/)|([^:][+]))$'