1*1debfc3dSmrg#!/bin/sh 2*1debfc3dSmrg 3*1debfc3dSmrg# Checks some of the GNU style formatting rules in a set of patches. 4*1debfc3dSmrg# Copyright (C) 2010, 2012, 2016 Free Software Foundation, Inc. 5*1debfc3dSmrg# Contributed by Sebastian Pop <sebastian.pop@amd.com> 6*1debfc3dSmrg 7*1debfc3dSmrg# This program is free software; you can redistribute it and/or modify 8*1debfc3dSmrg# it under the terms of the GNU General Public License as published by 9*1debfc3dSmrg# the Free Software Foundation; either version 3 of the License, or 10*1debfc3dSmrg# (at your option) any later version. 11*1debfc3dSmrg 12*1debfc3dSmrg# This program is distributed in the hope that it will be useful, 13*1debfc3dSmrg# but WITHOUT ANY WARRANTY; without even the implied warranty of 14*1debfc3dSmrg# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*1debfc3dSmrg# GNU General Public License for more details. 16*1debfc3dSmrg 17*1debfc3dSmrg# You should have received a copy of the GNU General Public License 18*1debfc3dSmrg# along with this program; if not, see the file COPYING3. If not, 19*1debfc3dSmrg# see <http://www.gnu.org/licenses/>. 20*1debfc3dSmrg 21*1debfc3dSmrg# Set to empty in the environment to override. 22*1debfc3dSmrg: ${color:---color=always} 23*1debfc3dSmrg 24*1debfc3dSmrgusage() { 25*1debfc3dSmrg cat <<EOF 26*1debfc3dSmrgcheck_GNU_style.sh [patch]... 27*1debfc3dSmrg 28*1debfc3dSmrg Checks the patches for some of the GNU style formatting problems. 29*1debfc3dSmrg When FILE is -, read standard input. 30*1debfc3dSmrg 31*1debfc3dSmrg Please note that these checks are not always accurate, and 32*1debfc3dSmrg complete. The reference documentation of the GNU Coding Standards 33*1debfc3dSmrg can be found here: http://www.gnu.org/prep/standards_toc.html 34*1debfc3dSmrg and there are also some additional coding conventions for GCC: 35*1debfc3dSmrg http://gcc.gnu.org/codingconventions.html 36*1debfc3dSmrg 37*1debfc3dSmrgEOF 38*1debfc3dSmrg exit 1 39*1debfc3dSmrg} 40*1debfc3dSmrg 41*1debfc3dSmrgtest $# -eq 0 && usage 42*1debfc3dSmrgnfiles=$# 43*1debfc3dSmrgfiles="$*" 44*1debfc3dSmrg 45*1debfc3dSmrgstdin=false 46*1debfc3dSmrgstdin_tmp="" 47*1debfc3dSmrgif [ $nfiles -eq 1 ] && [ "$files" = "-" ]; then 48*1debfc3dSmrg stdin=true 49*1debfc3dSmrg 50*1debfc3dSmrg # By putting stdin into a temp file, we can handle it just like any other 51*1debfc3dSmrg # file. F.i., we can cat it twice, which we can't do with stdin. 52*1debfc3dSmrg stdin_tmp=check_GNU_style.stdin 53*1debfc3dSmrg cat - > $stdin_tmp 54*1debfc3dSmrg files=$stdin_tmp 55*1debfc3dSmrgelse 56*1debfc3dSmrg for f in $files; do 57*1debfc3dSmrg if [ "$f" = "-" ]; then 58*1debfc3dSmrg # Let's keep things simple. Either we read from stdin, or we read 59*1debfc3dSmrg # from files specified on the command line, not both. 60*1debfc3dSmrg usage 61*1debfc3dSmrg fi 62*1debfc3dSmrg if [ ! -f "$f" ]; then 63*1debfc3dSmrg echo "error: could not read file: $f" 64*1debfc3dSmrg exit 1 65*1debfc3dSmrg fi 66*1debfc3dSmrg done 67*1debfc3dSmrgfi 68*1debfc3dSmrg 69*1debfc3dSmrginp=check_GNU_style.inp 70*1debfc3dSmrgtmp=check_GNU_style.tmp 71*1debfc3dSmrgtmp2=check_GNU_style.2.tmp 72*1debfc3dSmrgtmp3=check_GNU_style.3.tmp 73*1debfc3dSmrg 74*1debfc3dSmrg# Remove $tmp on exit and various signals. 75*1debfc3dSmrgtrap "rm -f $inp $tmp $tmp2 $tmp3 $stdin_tmp" 0 76*1debfc3dSmrgtrap "rm -f $inp $tmp $tmp2 $tmp3 $stdin_tmp; exit 1" 1 2 3 5 9 13 15 77*1debfc3dSmrg 78*1debfc3dSmrgif [ $nfiles -eq 1 ]; then 79*1debfc3dSmrg # There's no need for the file prefix if we're dealing only with one file. 80*1debfc3dSmrg format="-n" 81*1debfc3dSmrgelse 82*1debfc3dSmrg format="-nH" 83*1debfc3dSmrgfi 84*1debfc3dSmrg 85*1debfc3dSmrg# Remove the testsuite part of the diff. We don't care about GNU style 86*1debfc3dSmrg# in testcases and the dg-* directives give too many false positives. 87*1debfc3dSmrgremove_testsuite () 88*1debfc3dSmrg{ 89*1debfc3dSmrg awk 'BEGIN{testsuite=0} /^(.*:)?([1-9][0-9]*:)?\+\+\+ / && ! /testsuite\//{testsuite=0} \ 90*1debfc3dSmrg {if (!testsuite) print} /^(.*:)?([1-9][0-9]*:)?\+\+\+ (.*\/)?testsuite\//{testsuite=1}' 91*1debfc3dSmrg} 92*1debfc3dSmrg 93*1debfc3dSmrggrep $format '^+' $files \ 94*1debfc3dSmrg | remove_testsuite \ 95*1debfc3dSmrg | grep -v ':+++' \ 96*1debfc3dSmrg > $inp 97*1debfc3dSmrg 98*1debfc3dSmrgcat_with_prefix () 99*1debfc3dSmrg{ 100*1debfc3dSmrg local f="$1" 101*1debfc3dSmrg 102*1debfc3dSmrg if [ "$prefix" = "" ]; then 103*1debfc3dSmrg cat "$f" 104*1debfc3dSmrg else 105*1debfc3dSmrg awk "{printf \"%s%s\n\", \"$prefix\", \$0}" $f 106*1debfc3dSmrg fi 107*1debfc3dSmrg} 108*1debfc3dSmrg 109*1debfc3dSmrg# Grep 110*1debfc3dSmrgg (){ 111*1debfc3dSmrg local msg="$1" 112*1debfc3dSmrg local arg="$2" 113*1debfc3dSmrg 114*1debfc3dSmrg local found=false 115*1debfc3dSmrg cat $inp \ 116*1debfc3dSmrg | egrep $color -- "$arg" \ 117*1debfc3dSmrg > "$tmp" && found=true 118*1debfc3dSmrg 119*1debfc3dSmrg if $found; then 120*1debfc3dSmrg printf "\n$msg\n" 121*1debfc3dSmrg cat "$tmp" 122*1debfc3dSmrg fi 123*1debfc3dSmrg} 124*1debfc3dSmrg 125*1debfc3dSmrg# And Grep 126*1debfc3dSmrgag (){ 127*1debfc3dSmrg local msg="$1" 128*1debfc3dSmrg local arg1="$2" 129*1debfc3dSmrg local arg2="$3" 130*1debfc3dSmrg 131*1debfc3dSmrg local found=false 132*1debfc3dSmrg cat $inp \ 133*1debfc3dSmrg | egrep $color -- "$arg1" \ 134*1debfc3dSmrg | egrep $color -- "$arg2" \ 135*1debfc3dSmrg > "$tmp" && found=true 136*1debfc3dSmrg 137*1debfc3dSmrg if $found; then 138*1debfc3dSmrg printf "\n$msg\n" 139*1debfc3dSmrg cat "$tmp" 140*1debfc3dSmrg fi 141*1debfc3dSmrg} 142*1debfc3dSmrg 143*1debfc3dSmrg# reVerse Grep 144*1debfc3dSmrgvg (){ 145*1debfc3dSmrg local msg="$1" 146*1debfc3dSmrg local varg="$2" 147*1debfc3dSmrg local arg="$3" 148*1debfc3dSmrg 149*1debfc3dSmrg local found=false 150*1debfc3dSmrg cat $inp \ 151*1debfc3dSmrg | egrep -v -- "$varg" \ 152*1debfc3dSmrg | egrep $color -- "$arg" \ 153*1debfc3dSmrg > "$tmp" && found=true 154*1debfc3dSmrg 155*1debfc3dSmrg if $found; then 156*1debfc3dSmrg printf "\n$msg\n" 157*1debfc3dSmrg cat "$tmp" 158*1debfc3dSmrg fi 159*1debfc3dSmrg} 160*1debfc3dSmrg 161*1debfc3dSmrgcol (){ 162*1debfc3dSmrg local msg="$1" 163*1debfc3dSmrg 164*1debfc3dSmrg local first=true 165*1debfc3dSmrg local f 166*1debfc3dSmrg for f in $files; do 167*1debfc3dSmrg prefix="" 168*1debfc3dSmrg if [ $nfiles -ne 1 ]; then 169*1debfc3dSmrg prefix="$f:" 170*1debfc3dSmrg fi 171*1debfc3dSmrg 172*1debfc3dSmrg # Don't reuse $inp, which may be generated using -H and thus contain a 173*1debfc3dSmrg # file prefix. Re-remove the testsuite since we're not using $inp. 174*1debfc3dSmrg cat $f | remove_testsuite \ 175*1debfc3dSmrg | grep -n '^+' \ 176*1debfc3dSmrg | grep -v ':+++' \ 177*1debfc3dSmrg > $tmp 178*1debfc3dSmrg 179*1debfc3dSmrg # Keep only line number prefix and patch modifier '+'. 180*1debfc3dSmrg cat "$tmp" \ 181*1debfc3dSmrg | sed 's/\(^[0-9][0-9]*:+\).*/\1/' \ 182*1debfc3dSmrg > "$tmp2" 183*1debfc3dSmrg 184*1debfc3dSmrg # Remove line number prefix and patch modifier '+'. 185*1debfc3dSmrg # Expand tabs to spaces according to tab positions. 186*1debfc3dSmrg # Keep long lines, make short lines empty. Print the part past 80 chars 187*1debfc3dSmrg # in red. 188*1debfc3dSmrg cat "$tmp" \ 189*1debfc3dSmrg | sed 's/^[0-9]*:+//' \ 190*1debfc3dSmrg | expand \ 191*1debfc3dSmrg | awk '{ \ 192*1debfc3dSmrg if (length($0) > 80) \ 193*1debfc3dSmrg printf "%s\033[1;31m%s\033[0m\n", \ 194*1debfc3dSmrg substr($0,1,80), \ 195*1debfc3dSmrg substr($0,81); \ 196*1debfc3dSmrg else \ 197*1debfc3dSmrg print "" \ 198*1debfc3dSmrg }' \ 199*1debfc3dSmrg > "$tmp3" 200*1debfc3dSmrg 201*1debfc3dSmrg # Combine prefix back with long lines. 202*1debfc3dSmrg # Filter out empty lines. 203*1debfc3dSmrg local found=false 204*1debfc3dSmrg paste -d '\0' "$tmp2" "$tmp3" \ 205*1debfc3dSmrg | grep -v '^[0-9][0-9]*:+$' \ 206*1debfc3dSmrg > "$tmp" && found=true 207*1debfc3dSmrg 208*1debfc3dSmrg if $found; then 209*1debfc3dSmrg if $first; then 210*1debfc3dSmrg printf "\n$msg\n" 211*1debfc3dSmrg first=false 212*1debfc3dSmrg fi 213*1debfc3dSmrg cat_with_prefix "$tmp" 214*1debfc3dSmrg fi 215*1debfc3dSmrg done 216*1debfc3dSmrg} 217*1debfc3dSmrg 218*1debfc3dSmrg 219*1debfc3dSmrgcol 'Lines should not exceed 80 characters.' 220*1debfc3dSmrg 221*1debfc3dSmrgg 'Blocks of 8 spaces should be replaced with tabs.' \ 222*1debfc3dSmrg ' {8}' 223*1debfc3dSmrg 224*1debfc3dSmrgg 'Trailing whitespace.' \ 225*1debfc3dSmrg '[[:space:]]$' 226*1debfc3dSmrg 227*1debfc3dSmrgg 'Space before dot.' \ 228*1debfc3dSmrg '[[:alnum:]][[:blank:]]+\.' 229*1debfc3dSmrg 230*1debfc3dSmrgg 'Dot, space, space, new sentence.' \ 231*1debfc3dSmrg '[[:alnum:]]\.([[:blank:]]|[[:blank:]]{3,})[A-Z0-9]' 232*1debfc3dSmrg 233*1debfc3dSmrgg 'Dot, space, space, end of comment.' \ 234*1debfc3dSmrg '[[:alnum:]]\.([[:blank:]]{0,1}|[[:blank:]]{3,})\*/' 235*1debfc3dSmrg 236*1debfc3dSmrgg 'Sentences should end with a dot. Dot, space, space, end of the comment.' \ 237*1debfc3dSmrg '[[:alnum:]][[:blank:]]*\*/' 238*1debfc3dSmrg 239*1debfc3dSmrgvg 'There should be exactly one space between function name and parenthesis.' \ 240*1debfc3dSmrg '\#define' \ 241*1debfc3dSmrg '[[:alnum:]]([[:blank:]]{2,})?\(' 242*1debfc3dSmrg 243*1debfc3dSmrgg 'There should be no space before a left square bracket.' \ 244*1debfc3dSmrg '[[:alnum:]][[:blank:]]+\[' 245*1debfc3dSmrg 246*1debfc3dSmrgg 'There should be no space before closing parenthesis.' \ 247*1debfc3dSmrg '[[:graph:]][[:blank:]]+\)' 248*1debfc3dSmrg 249*1debfc3dSmrg# This will give false positives for C99 compound literals. 250*1debfc3dSmrgg 'Braces should be on a separate line.' \ 251*1debfc3dSmrg '(\)|else)[[:blank:]]*{' 252*1debfc3dSmrg 253*1debfc3dSmrg# Does this apply to definitions of aggregate objects? 254*1debfc3dSmrgag 'Trailing operator.' \ 255*1debfc3dSmrg '^[1-9][0-9]*:\+[[:space:]]' \ 256*1debfc3dSmrg '(([^a-zA-Z_]\*)|([-%<=&|^?])|([^*]/)|([^:][+]))$' 257