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

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