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

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