~youscribe/parted/3.1

« back to all changes in this revision

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

  • Committer: Guilhem Lettron
  • Date: 2012-10-22 14:37:59 UTC
  • Revision ID: guilhem+ubuntu@lettron.fr-20121022143759-m403kecgz13sknvp
3.1 from tarball

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