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

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