~peter-pearse/ubuntu/natty/diffutils/prop001

« back to all changes in this revision

Viewing changes to build-aux/useless-if-before-free

  • Committer: Bazaar Package Importer
  • Author(s): Santiago Vila
  • Date: 2010-05-04 20:38:00 UTC
  • mfrom: (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100504203800-f67xd9rsa9xl9qqj
Tags: 1:3.0-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
eval '(exit $?0)' && eval 'exec perl -wST "$0" ${1+"$@"}'
 
2
  & eval 'exec perl -wST "$0" $argv:q'
 
3
    if 0;
 
4
# Detect instances of "if (p) free (p);".
 
5
# Likewise for "if (p != NULL) free (p);".  And with braces.
 
6
# Also detect "if (NULL != p) free (p);".
 
7
# And with 0 in place of NULL.
 
8
 
 
9
my $VERSION = '2009-04-16 15:57'; # UTC
 
10
# The definition above must lie within the first 8 lines in order
 
11
# for the Emacs time-stamp write hook (at end) to update it.
 
12
# If you change this file with Emacs, please let the write hook
 
13
# do its job.  Otherwise, update this string manually.
 
14
 
 
15
# Copyright (C) 2008-2010 Free Software Foundation, Inc.
 
16
 
 
17
# This program is free software: you can redistribute it and/or modify
 
18
# it under the terms of the GNU General Public License as published by
 
19
# the Free Software Foundation, either version 3 of the License, or
 
20
# (at your option) any later version.
 
21
 
 
22
# This program is distributed in the hope that it will be useful,
 
23
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
24
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
25
# GNU General Public License for more details.
 
26
 
 
27
# You should have received a copy of the GNU General Public License
 
28
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
29
 
 
30
# Written by Jim Meyering
 
31
 
 
32
use strict;
 
33
use warnings;
 
34
use Getopt::Long;
 
35
 
 
36
(my $ME = $0) =~ s|.*/||;
 
37
 
 
38
# use File::Coda; # http://meyering.net/code/Coda/
 
39
END {
 
40
  defined fileno STDOUT or return;
 
41
  close STDOUT and return;
 
42
  warn "$ME: failed to close standard output: $!\n";
 
43
  $? ||= 1;
 
44
}
 
45
 
 
46
sub usage ($)
 
47
{
 
48
  my ($exit_code) = @_;
 
49
  my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
 
50
  if ($exit_code != 0)
 
51
    {
 
52
      print $STREAM "Try `$ME --help' for more information.\n";
 
53
    }
 
54
  else
 
55
    {
 
56
      print $STREAM <<EOF;
 
57
Usage: $ME [OPTIONS] FILE...
 
58
 
 
59
Detect any instance in FILE of a useless "if" test before a free call, e.g.,
 
60
"if (p) free (p);".  Any such test may be safely removed without affecting
 
61
the semantics of the C code in FILE.  Use --name=FOO --name=BAR to also
 
62
detect free-like functions named FOO and BAR.
 
63
 
 
64
OPTIONS:
 
65
 
 
66
   --list       print only the name of each matching FILE (\0-terminated)
 
67
   --name=N     add name N to the list of \`free\'-like functions to detect;
 
68
                  may be repeated
 
69
 
 
70
   --help       display this help and exit
 
71
   --version    output version information and exit
 
72
 
 
73
Exit status:
 
74
 
 
75
  0   one or more matches
 
76
  1   no match
 
77
  2   an error
 
78
 
 
79
EXAMPLE:
 
80
 
 
81
For example, this command prints all removable "if" tests before "free"
 
82
and "kfree" calls in the linux kernel sources:
 
83
 
 
84
    git ls-files -z |xargs -0 $ME --name=kfree
 
85
 
 
86
EOF
 
87
    }
 
88
  exit $exit_code;
 
89
}
 
90
 
 
91
sub is_NULL ($)
 
92
{
 
93
  my ($expr) = @_;
 
94
  return ($expr eq 'NULL' || $expr eq '0');
 
95
}
 
96
 
 
97
{
 
98
  sub EXIT_MATCH {0}
 
99
  sub EXIT_NO_MATCH {1}
 
100
  sub EXIT_ERROR {2}
 
101
  my $err = EXIT_NO_MATCH;
 
102
 
 
103
  my $list;
 
104
  my @name = qw(free);
 
105
  GetOptions
 
106
    (
 
107
     help => sub { usage 0 },
 
108
     version => sub { print "$ME version $VERSION\n"; exit },
 
109
     list => \$list,
 
110
     'name=s@' => \@name,
 
111
    ) or usage 1;
 
112
 
 
113
  # Make sure we have the right number of non-option arguments.
 
114
  # Always tell the user why we fail.
 
115
  @ARGV < 1
 
116
    and (warn "$ME: missing FILE argument\n"), usage EXIT_ERROR;
 
117
 
 
118
  my $or = join '|', @name;
 
119
  my $regexp = qr/(?:$or)/;
 
120
 
 
121
  # Set the input record separator.
 
122
  # Note: this makes it impractical to print line numbers.
 
123
  $/ = '"';
 
124
 
 
125
  my $found_match = 0;
 
126
 FILE:
 
127
  foreach my $file (@ARGV)
 
128
    {
 
129
      open FH, '<', $file
 
130
        or (warn "$ME: can't open `$file' for reading: $!\n"),
 
131
          $err = EXIT_ERROR, next;
 
132
      while (defined (my $line = <FH>))
 
133
        {
 
134
          while ($line =~
 
135
              /\b(if\s*\(\s*([^)]+?)(?:\s*!=\s*([^)]+?))?\s*\)
 
136
              #  1          2                  3
 
137
               (?:   \s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)|
 
138
                \s*\{\s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;\s*\}))/sxg)
 
139
            {
 
140
              my $all = $1;
 
141
              my ($lhs, $rhs) = ($2, $3);
 
142
              my ($free_opnd, $braced_free_opnd) = ($4, $5);
 
143
              my $non_NULL;
 
144
              if (!defined $rhs) { $non_NULL = $lhs }
 
145
              elsif (is_NULL $rhs) { $non_NULL = $lhs }
 
146
              elsif (is_NULL $lhs) { $non_NULL = $rhs }
 
147
              else { next }
 
148
 
 
149
              # Compare the non-NULL part of the "if" expression and the
 
150
              # free'd expression, without regard to white space.
 
151
              $non_NULL =~ tr/ \t//d;
 
152
              my $e2 = defined $free_opnd ? $free_opnd : $braced_free_opnd;
 
153
              $e2 =~ tr/ \t//d;
 
154
              if ($non_NULL eq $e2)
 
155
                {
 
156
                  $found_match = 1;
 
157
                  $list
 
158
                    and (print "$file\0"), next FILE;
 
159
                  print "$file: $all\n";
 
160
                }
 
161
            }
 
162
        }
 
163
    }
 
164
  continue
 
165
    {
 
166
      close FH;
 
167
    }
 
168
 
 
169
  $found_match && $err == EXIT_NO_MATCH
 
170
    and $err = EXIT_MATCH;
 
171
 
 
172
  exit $err;
 
173
}
 
174
 
 
175
my $foo = <<'EOF';
 
176
# The above is to *find* them.
 
177
# This adjusts them, removing the unnecessary "if (p)" part.
 
178
 
 
179
# FIXME: do something like this as an option (doesn't do braces):
 
180
free=xfree
 
181
git grep -l -z "$free *(" \
 
182
  | xargs -0 useless-if-before-free -l --name="$free" \
 
183
  | xargs -0 perl -0x3b -pi -e \
 
184
   's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s+('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\))/$2/s'
 
185
 
 
186
# Use the following to remove redundant uses of kfree inside braces.
 
187
# Note that -0777 puts perl in slurp-whole-file mode;
 
188
# but we have plenty of memory, these days...
 
189
free=kfree
 
190
git grep -l -z "$free *(" \
 
191
  | xargs -0 useless-if-before-free -l --name="$free" \
 
192
  | xargs -0 perl -0777 -pi -e \
 
193
     's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s*\{\s*('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\);)\s*\}[^\n]*$/$2/gms'
 
194
 
 
195
Be careful that the result of the above transformation is valid.
 
196
If the matched string is followed by "else", then obviously, it won't be.
 
197
 
 
198
When modifying files, refuse to process anything other than a regular file.
 
199
EOF
 
200
 
 
201
## Local Variables:
 
202
## mode: perl
 
203
## indent-tabs-mode: nil
 
204
## eval: (add-hook 'write-file-hooks 'time-stamp)
 
205
## time-stamp-start: "my $VERSION = '"
 
206
## time-stamp-format: "%:y-%02m-%02d %02H:%02M"
 
207
## time-stamp-time-zone: "UTC"
 
208
## time-stamp-end: "'; # UTC"
 
209
## End: