1598 lines · 41.8 KB · Perl
RawDownload
#!/usr/bin/perl -w# (c) 2001, Dave Jones. <davej@codemonkey.org.uk> (the file handling bit)# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)# (c) 2007, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite, etc)# Licensed under the terms of the GNU GPL License version 2 use strict; my $P = $0;$P =~ s@.*/@@g; my $V = '0.12'; use Getopt::Long qw(:config no_auto_abbrev); my $quiet = 0;my $tree = 1;my $chk_signoff = 1;my $chk_patch = 1;my $tst_type = 0;my $emacs = 0;my $terse = 0;my $file = 0;my $check = 0;my $summary = 1;my $mailback = 0;my $root;GetOptions(	'q|quiet+'	=> \$quiet,	'tree!'		=> \$tree,	'signoff!'	=> \$chk_signoff,	'patch!'	=> \$chk_patch,	'test-type!'	=> \$tst_type,	'emacs!'	=> \$emacs,	'terse!'	=> \$terse,	'file!'		=> \$file,	'subjective!'	=> \$check,	'strict!'	=> \$check,	'root=s'	=> \$root,	'summary!'	=> \$summary,	'mailback!'	=> \$mailback,) or exit; my $exit = 0; if ($#ARGV < 0) {	print "usage: $P [options] patchfile\n";	print "version: $V\n";	print "options: -q           => quiet\n";	print "         --no-tree    => run without a kernel tree\n";	print "         --terse      => one line per report\n";	print "         --emacs      => emacs compile window format\n";	print "         --file       => check a source file\n";	print "         --strict     => enable more subjective tests\n";	print "         --root       => path to the kernel tree root\n";	exit(1);} if ($terse) {	$emacs = 1;	$quiet++;} if ($tree) {	if (defined $root) {		if (!top_of_kernel_tree($root)) {			die "$P: $root: --root does not point at a valid tree\n";		}	} else {		if (top_of_kernel_tree('.')) {			$root = '.';		} elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&						top_of_kernel_tree($1)) {			$root = $1;		}	} 	if (!defined $root) {		print "Must be run from the top-level dir. of a kernel tree\n";		exit(2);	}} my $emitted_corrupt = 0; our $Ident       = qr{[A-Za-z_][A-Za-z\d_]*};our $Storage	= qr{extern|static|asmlinkage};our $Sparse	= qr{			__user|			__kernel|			__force|			__iomem|			__must_check|			__init_refok|			__kprobes|			fastcall		}x;our $Attribute	= qr{			const|			__read_mostly|			__kprobes|			__(?:mem|cpu|dev|)(?:initdata|init)		  }x;our $Inline	= qr{inline|__always_inline|noinline};our $Member	= qr{->$Ident|\.$Ident|\[[^]]*\]};our $Lval	= qr{$Ident(?:$Member)*}; our $Constant	= qr{(?:[0-9]+|0x[0-9a-fA-F]+)[UL]*};our $Assignment	= qr{(?:\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=)};our $Operators	= qr{			<=|>=|==|!=|			=>|->|<<|>>|<|>|!|~|			&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/		  }x; our $NonptrType;our $Type;our $Declare; our @typeList = (	qr{void},	qr{char},	qr{short},	qr{int},	qr{long},	qr{unsigned},	qr{float},	qr{double},	qr{bool},	qr{long\s+int},	qr{long\s+long},	qr{long\s+long\s+int},	qr{(?:__)?(?:u|s|be|le)(?:8|16|32|64)},	qr{struct\s+$Ident},	qr{union\s+$Ident},	qr{enum\s+$Ident},	qr{${Ident}_t},	qr{${Ident}_handler},	qr{${Ident}_handler_fn},); sub build_types {	my $all = "(?:  \n" . join("|\n  ", @typeList) . "\n)";	$NonptrType	= qr{			\b			(?:const\s+)?			(?:unsigned\s+)?			$all			(?:\s+$Sparse|\s+const)*			\b		  }x;	$Type	= qr{			\b$NonptrType\b			(?:\s*\*+\s*const|\s*\*+|(?:\s*\[\s*\])+)?			(?:\s+$Sparse|\s+$Attribute)*		  }x;	$Declare	= qr{(?:$Storage\s+)?$Type};}build_types(); $chk_signoff = 0 if ($file); my @dep_includes = ();my @dep_functions = ();my $removal = "Documentation/feature-removal-schedule.txt";if ($tree && -f "$root/$removal") {	open(REMOVE, "<$root/$removal") ||				die "$P: $removal: open failed - $!\n";	while (<REMOVE>) {		if (/^Check:\s+(.*\S)/) {			for my $entry (split(/[, ]+/, $1)) {				if ($entry =~ m@include/(.*)@) {					push(@dep_includes, $1); 				} elsif ($entry !~ m@/@) {					push(@dep_functions, $entry);				}			}		}	}} my @rawlines = ();for my $filename (@ARGV) {	if ($file) {		open(FILE, "diff -u /dev/null $filename|") ||			die "$P: $filename: diff failed - $!\n";	} else {		open(FILE, "<$filename") ||			die "$P: $filename: open failed - $!\n";	}	while (<FILE>) {		chomp;		push(@rawlines, $_);	}	close(FILE);	if (!process($filename, @rawlines)) {		$exit = 1;	}	@rawlines = ();} exit($exit); sub top_of_kernel_tree {	my ($root) = @_; 	my @tree_check = (		"COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",		"README", "Documentation", "arch", "include", "drivers",		"fs", "init", "ipc", "kernel", "lib", "scripts",	); 	foreach my $check (@tree_check) {		if (! -e $root . '/' . $check) {			return 0;		}	}	return 1;} sub expand_tabs {	my ($str) = @_; 	my $res = '';	my $n = 0;	for my $c (split(//, $str)) {		if ($c eq "\t") {			$res .= ' ';			$n++;			for (; ($n % 8) != 0; $n++) {				$res .= ' ';			}			next;		}		$res .= $c;		$n++;	} 	return $res;}sub copy_spacing {	my ($str) = @_; 	my $res = '';	for my $c (split(//, $str)) {		if ($c eq "\t") {			$res .= $c;		} else {			$res .= ' ';		}	} 	return $res;} sub line_stats {	my ($line) = @_; 	# Drop the diff line leader and expand tabs	$line =~ s/^.//;	$line = expand_tabs($line); 	# Pick the indent from the front of the line.	my ($white) = ($line =~ /^(\s*)/); 	return (length($line), length($white));} sub sanitise_line {	my ($line) = @_; 	my $res = '';	my $l = ''; 	my $quote = ''; 	foreach my $c (split(//, $line)) {		if ($l ne "\\" && ($c eq "'" || $c eq '"')) {			if ($quote eq '') {				$quote = $c;				$res .= $c;				$l = $c;				next;			} elsif ($quote eq $c) {				$quote = '';			}		}		if ($quote && $c ne "\t") {			$res .= "X";		} else {			$res .= $c;		} 		$l = $c;	} 	return $res;} sub ctx_statement_block {	my ($linenr, $remain, $off) = @_;	my $line = $linenr - 1;	my $blk = '';	my $soff = $off;	my $coff = $off - 1; 	my $type = '';	my $level = 0;	my $c;	my $len = 0;	while (1) {		#warn "CSB: blk<$blk>\n";		# If we are about to drop off the end, pull in more		# context.		if ($off >= $len) {			for (; $remain > 0; $line++) {				next if ($rawlines[$line] =~ /^-/);				$remain--;				$blk .= sanitise_line($rawlines[$line]) . "\n";				$len = length($blk);				$line++;				last;			}			# Bail if there is no further context.			#warn "CSB: blk<$blk> off<$off> len<$len>\n";			if ($off == $len) {				last;			}		}		$c = substr($blk, $off, 1); 		#warn "CSB: c<$c> type<$type> level<$level>\n";		# Statement ends at the ';' or a close '}' at the		# outermost level.		if ($level == 0 && $c eq ';') {			last;		} 		if (($type eq '' || $type eq '(') && $c eq '(') {			$level++;			$type = '(';		}		if ($type eq '(' && $c eq ')') {			$level--;			$type = ($level != 0)? '(' : ''; 			if ($level == 0 && $coff < $soff) {				$coff = $off;			}		}		if (($type eq '' || $type eq '{') && $c eq '{') {			$level++;			$type = '{';		}		if ($type eq '{' && $c eq '}') {			$level--;			$type = ($level != 0)? '{' : ''; 			if ($level == 0) {				last;			}		}		$off++;	} 	my $statement = substr($blk, $soff, $off - $soff + 1);	my $condition = substr($blk, $soff, $coff - $soff + 1); 	#warn "STATEMENT<$statement>\n";	#warn "CONDITION<$condition>\n"; 	return ($statement, $condition);} sub ctx_block_get {	my ($linenr, $remain, $outer, $open, $close, $off) = @_;	my $line;	my $start = $linenr - 1;	my $blk = '';	my @o;	my @c;	my @res = (); 	my $level = 0;	for ($line = $start; $remain > 0; $line++) {		next if ($rawlines[$line] =~ /^-/);		$remain--; 		$blk .= $rawlines[$line];		foreach my $c (split(//, $rawlines[$line])) {			##print "C<$c>L<$level><$open$close>O<$off>\n";			if ($off > 0) {				$off--;				next;			} 			if ($c eq $close && $level > 0) {				$level--;				last if ($level == 0);			} elsif ($c eq $open) {				$level++;			}		} 		if (!$outer || $level <= 1) {			push(@res, $rawlines[$line]);		} 		last if ($level == 0);	} 	return ($level, @res);}sub ctx_block_outer {	my ($linenr, $remain) = @_; 	my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);	return @r;}sub ctx_block {	my ($linenr, $remain) = @_; 	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);	return @r;}sub ctx_statement {	my ($linenr, $remain, $off) = @_; 	my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);	return @r;}sub ctx_block_level {	my ($linenr, $remain) = @_; 	return ctx_block_get($linenr, $remain, 0, '{', '}', 0);}sub ctx_statement_level {	my ($linenr, $remain, $off) = @_; 	return ctx_block_get($linenr, $remain, 0, '(', ')', $off);} sub ctx_locate_comment {	my ($first_line, $end_line) = @_; 	# Catch a comment on the end of the line itself.	my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*$@);	return $current_comment if (defined $current_comment); 	# Look through the context and try and figure out if there is a	# comment.	my $in_comment = 0;	$current_comment = '';	for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {		my $line = $rawlines[$linenr - 1];		#warn "           $line\n";		if ($linenr == $first_line and $line =~ m@^.\s*\*@) {			$in_comment = 1;		}		if ($line =~ m@/\*@) {			$in_comment = 1;		}		if (!$in_comment && $current_comment ne '') {			$current_comment = '';		}		$current_comment .= $line . "\n" if ($in_comment);		if ($line =~ m@\*/@) {			$in_comment = 0;		}	} 	chomp($current_comment);	return($current_comment);}sub ctx_has_comment {	my ($first_line, $end_line) = @_;	my $cmt = ctx_locate_comment($first_line, $end_line); 	##print "LINE: $rawlines[$end_line - 1 ]\n";	##print "CMMT: $cmt\n"; 	return ($cmt ne '');} sub cat_vet {	my ($vet) = @_;	my ($res, $coded); 	$res = '';	while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {		$res .= $1;		if ($2 ne '') {			$coded = sprintf("^%c", unpack('C', $2) + 64);			$res .= $coded;		}	}	$res =~ s/$/\$/; 	return $res;

Lines 1–500 of 1598.