Blame build-aux/useless-if-before-free

Packit Service c3aa71
eval '(exit $?0)' && eval 'exec perl -wST "$0" ${1+"$@"}'
Packit Service c3aa71
  & eval 'exec perl -wST "$0" $argv:q'
Packit Service c3aa71
    if 0;
Packit Service c3aa71
# Detect instances of "if (p) free (p);".
Packit Service c3aa71
# Likewise "if (p != 0)", "if (0 != p)", or with NULL; and with braces.
Packit Service c3aa71
Packit Service c3aa71
my $VERSION = '2012-01-06 07:23'; # UTC
Packit Service c3aa71
# The definition above must lie within the first 8 lines in order
Packit Service c3aa71
# for the Emacs time-stamp write hook (at end) to update it.
Packit Service c3aa71
# If you change this file with Emacs, please let the write hook
Packit Service c3aa71
# do its job.  Otherwise, update this string manually.
Packit Service c3aa71
Packit Service c3aa71
# Copyright (C) 2008-2015 Free Software Foundation, Inc.
Packit Service c3aa71
Packit Service c3aa71
# This program is free software: you can redistribute it and/or modify
Packit Service c3aa71
# it under the terms of the GNU General Public License as published by
Packit Service c3aa71
# the Free Software Foundation, either version 3 of the License, or
Packit Service c3aa71
# (at your option) any later version.
Packit Service c3aa71
Packit Service c3aa71
# This program is distributed in the hope that it will be useful,
Packit Service c3aa71
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service c3aa71
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service c3aa71
# GNU General Public License for more details.
Packit Service c3aa71
Packit Service c3aa71
# You should have received a copy of the GNU General Public License
Packit Service c3aa71
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service c3aa71
Packit Service c3aa71
# Written by Jim Meyering
Packit Service c3aa71
Packit Service c3aa71
use strict;
Packit Service c3aa71
use warnings;
Packit Service c3aa71
use Getopt::Long;
Packit Service c3aa71
Packit Service c3aa71
(my $ME = $0) =~ s|.*/||;
Packit Service c3aa71
Packit Service c3aa71
# use File::Coda; # http://meyering.net/code/Coda/
Packit Service c3aa71
END {
Packit Service c3aa71
  defined fileno STDOUT or return;
Packit Service c3aa71
  close STDOUT and return;
Packit Service c3aa71
  warn "$ME: failed to close standard output: $!\n";
Packit Service c3aa71
  $? ||= 1;
Packit Service c3aa71
}
Packit Service c3aa71
Packit Service c3aa71
sub usage ($)
Packit Service c3aa71
{
Packit Service c3aa71
  my ($exit_code) = @_;
Packit Service c3aa71
  my $STREAM = ($exit_code == 0 ? *STDOUT : *STDERR);
Packit Service c3aa71
  if ($exit_code != 0)
Packit Service c3aa71
    {
Packit Service c3aa71
      print $STREAM "Try '$ME --help' for more information.\n";
Packit Service c3aa71
    }
Packit Service c3aa71
  else
Packit Service c3aa71
    {
Packit Service c3aa71
      print $STREAM <
Packit Service c3aa71
Usage: $ME [OPTIONS] FILE...
Packit Service c3aa71
Packit Service c3aa71
Detect any instance in FILE of a useless "if" test before a free call, e.g.,
Packit Service c3aa71
"if (p) free (p);".  Any such test may be safely removed without affecting
Packit Service c3aa71
the semantics of the C code in FILE.  Use --name=FOO --name=BAR to also
Packit Service c3aa71
detect free-like functions named FOO and BAR.
Packit Service c3aa71
Packit Service c3aa71
OPTIONS:
Packit Service c3aa71
Packit Service c3aa71
   --list       print only the name of each matching FILE (\\0-terminated)
Packit Service c3aa71
   --name=N     add name N to the list of \'free\'-like functions to detect;
Packit Service c3aa71
                  may be repeated
Packit Service c3aa71
Packit Service c3aa71
   --help       display this help and exit
Packit Service c3aa71
   --version    output version information and exit
Packit Service c3aa71
Packit Service c3aa71
Exit status:
Packit Service c3aa71
Packit Service c3aa71
  0   one or more matches
Packit Service c3aa71
  1   no match
Packit Service c3aa71
  2   an error
Packit Service c3aa71
Packit Service c3aa71
EXAMPLE:
Packit Service c3aa71
Packit Service c3aa71
For example, this command prints all removable "if" tests before "free"
Packit Service c3aa71
and "kfree" calls in the linux kernel sources:
Packit Service c3aa71
Packit Service c3aa71
    git ls-files -z |xargs -0 $ME --name=kfree
Packit Service c3aa71
Packit Service c3aa71
EOF
Packit Service c3aa71
    }
Packit Service c3aa71
  exit $exit_code;
Packit Service c3aa71
}
Packit Service c3aa71
Packit Service c3aa71
sub is_NULL ($)
Packit Service c3aa71
{
Packit Service c3aa71
  my ($expr) = @_;
Packit Service c3aa71
  return ($expr eq 'NULL' || $expr eq '0');
Packit Service c3aa71
}
Packit Service c3aa71
Packit Service c3aa71
{
Packit Service c3aa71
  sub EXIT_MATCH {0}
Packit Service c3aa71
  sub EXIT_NO_MATCH {1}
Packit Service c3aa71
  sub EXIT_ERROR {2}
Packit Service c3aa71
  my $err = EXIT_NO_MATCH;
Packit Service c3aa71
Packit Service c3aa71
  my $list;
Packit Service c3aa71
  my @name = qw(free);
Packit Service c3aa71
  GetOptions
Packit Service c3aa71
    (
Packit Service c3aa71
     help => sub { usage 0 },
Packit Service c3aa71
     version => sub { print "$ME version $VERSION\n"; exit },
Packit Service c3aa71
     list => \$list,
Packit Service c3aa71
     'name=s@' => \@name,
Packit Service c3aa71
    ) or usage 1;
Packit Service c3aa71
Packit Service c3aa71
  # Make sure we have the right number of non-option arguments.
Packit Service c3aa71
  # Always tell the user why we fail.
Packit Service c3aa71
  @ARGV < 1
Packit Service c3aa71
    and (warn "$ME: missing FILE argument\n"), usage EXIT_ERROR;
Packit Service c3aa71
Packit Service c3aa71
  my $or = join '|', @name;
Packit Service c3aa71
  my $regexp = qr/(?:$or)/;
Packit Service c3aa71
Packit Service c3aa71
  # Set the input record separator.
Packit Service c3aa71
  # Note: this makes it impractical to print line numbers.
Packit Service c3aa71
  $/ = '"';
Packit Service c3aa71
Packit Service c3aa71
  my $found_match = 0;
Packit Service c3aa71
 FILE:
Packit Service c3aa71
  foreach my $file (@ARGV)
Packit Service c3aa71
    {
Packit Service c3aa71
      open FH, '<', $file
Packit Service c3aa71
        or (warn "$ME: can't open '$file' for reading: $!\n"),
Packit Service c3aa71
          $err = EXIT_ERROR, next;
Packit Service c3aa71
      while (defined (my $line = <FH>))
Packit Service c3aa71
        {
Packit Service c3aa71
          while ($line =~
Packit Service c3aa71
              /\b(if\s*\(\s*([^)]+?)(?:\s*!=\s*([^)]+?))?\s*\)
Packit Service c3aa71
              #  1          2                  3
Packit Service c3aa71
               (?:   \s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;|
Packit Service c3aa71
                \s*\{\s*$regexp\s*\((?:\s*\([^)]+\))?\s*([^)]+)\)\s*;\s*\}))/sxg)
Packit Service c3aa71
            {
Packit Service c3aa71
              my $all = $1;
Packit Service c3aa71
              my ($lhs, $rhs) = ($2, $3);
Packit Service c3aa71
              my ($free_opnd, $braced_free_opnd) = ($4, $5);
Packit Service c3aa71
              my $non_NULL;
Packit Service c3aa71
              if (!defined $rhs) { $non_NULL = $lhs }
Packit Service c3aa71
              elsif (is_NULL $rhs) { $non_NULL = $lhs }
Packit Service c3aa71
              elsif (is_NULL $lhs) { $non_NULL = $rhs }
Packit Service c3aa71
              else { next }
Packit Service c3aa71
Packit Service c3aa71
              # Compare the non-NULL part of the "if" expression and the
Packit Service c3aa71
              # free'd expression, without regard to white space.
Packit Service c3aa71
              $non_NULL =~ tr/ \t//d;
Packit Service c3aa71
              my $e2 = defined $free_opnd ? $free_opnd : $braced_free_opnd;
Packit Service c3aa71
              $e2 =~ tr/ \t//d;
Packit Service c3aa71
              if ($non_NULL eq $e2)
Packit Service c3aa71
                {
Packit Service c3aa71
                  $found_match = 1;
Packit Service c3aa71
                  $list
Packit Service c3aa71
                    and (print "$file\0"), next FILE;
Packit Service c3aa71
                  print "$file: $all\n";
Packit Service c3aa71
                }
Packit Service c3aa71
            }
Packit Service c3aa71
        }
Packit Service c3aa71
    }
Packit Service c3aa71
  continue
Packit Service c3aa71
    {
Packit Service c3aa71
      close FH;
Packit Service c3aa71
    }
Packit Service c3aa71
Packit Service c3aa71
  $found_match && $err == EXIT_NO_MATCH
Packit Service c3aa71
    and $err = EXIT_MATCH;
Packit Service c3aa71
Packit Service c3aa71
  exit $err;
Packit Service c3aa71
}
Packit Service c3aa71
Packit Service c3aa71
my $foo = <<'EOF';
Packit Service c3aa71
# The above is to *find* them.
Packit Service c3aa71
# This adjusts them, removing the unnecessary "if (p)" part.
Packit Service c3aa71
Packit Service c3aa71
# FIXME: do something like this as an option (doesn't do braces):
Packit Service c3aa71
free=xfree
Packit Service c3aa71
git grep -l -z "$free *(" \
Packit Service c3aa71
  | xargs -0 useless-if-before-free -l --name="$free" \
Packit Service c3aa71
  | xargs -0 perl -0x3b -pi -e \
Packit Service c3aa71
   's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s+('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\)\s*;)/$2/s'
Packit Service c3aa71
Packit Service c3aa71
# Use the following to remove redundant uses of kfree inside braces.
Packit Service c3aa71
# Note that -0777 puts perl in slurp-whole-file mode;
Packit Service c3aa71
# but we have plenty of memory, these days...
Packit Service c3aa71
free=kfree
Packit Service c3aa71
git grep -l -z "$free *(" \
Packit Service c3aa71
  | xargs -0 useless-if-before-free -l --name="$free" \
Packit Service c3aa71
  | xargs -0 perl -0777 -pi -e \
Packit Service c3aa71
     's/\bif\s*\(\s*(\S+?)(?:\s*!=\s*(?:0|NULL))?\s*\)\s*\{\s*('"$free"'\s*\((?:\s*\([^)]+\))?\s*\1\s*\);)\s*\}[^\n]*$/$2/gms'
Packit Service c3aa71
Packit Service c3aa71
Be careful that the result of the above transformation is valid.
Packit Service c3aa71
If the matched string is followed by "else", then obviously, it won't be.
Packit Service c3aa71
Packit Service c3aa71
When modifying files, refuse to process anything other than a regular file.
Packit Service c3aa71
EOF
Packit Service c3aa71
Packit Service c3aa71
## Local Variables:
Packit Service c3aa71
## mode: perl
Packit Service c3aa71
## indent-tabs-mode: nil
Packit Service c3aa71
## eval: (add-hook 'write-file-hooks 'time-stamp)
Packit Service c3aa71
## time-stamp-start: "my $VERSION = '"
Packit Service c3aa71
## time-stamp-format: "%:y-%02m-%02d %02H:%02M"
Packit Service c3aa71
## time-stamp-time-zone: "UTC"
Packit Service c3aa71
## time-stamp-end: "'; # UTC"
Packit Service c3aa71
## End: