my $eol = qr/\015|\012|\015\012/;
####
$hash{
$something + $long / $and * $hairy
} = $foo;
##
##
if ( /blah (foo) gibber/ )
{
$var =~ s/\Q$1\E/bar/g;
}
##
##
if ( /blah (foo) gibber/ )
{
my $thingy = $1;
$var =~ s/\Q$thingy\E/bar/g;
}
##
##
$file =~ s/<<(\w+);.*\n\1\n//sg;
##
##
print <##
$file =~ s/[;\n]\s*#[^\n]*//sg; # Delete comments
##
##
print "foo; #bar";
##
##
print <##
print <##
sub twiddle ( $ )
{
my ( $arg ) = @_;
...
}
##
##
LOOP:
for ( my $I = do { ... }; $i < 20; ++$i ) { ... }
##
##
#!/usr/bin/perl
require 5.006;
use strict;
use warnings;
# Copyright (c) 2004 Barry Kaminsky. All rights reserved. This program
# is free software; you can redistribute it and/or modify it under the
# same terms as Perl itself.
# Last minute changes made May 2, 2004, 4:00 AM EST without much
# testing
# VarStructor is an alternative to Perl's reset function, which is
# expected to be deprecated. It could also be used to print variables
# and their values, including "my" variables. See comments at top of
# sub VARSTRUCTOR for configuration information.
#################################
# Test variables (could be deleted)
%hash1=("key1"=>"value1","key2"=>"value2");
$hash2{"key1"}="value1";
$hash2{"key2"}="value2";
$Simple_Var = 'simple';
@Simple_Arr = ('simple1','simple2');
#################################
&VARSTRUCTOR('show', 'E: subs(VARSTRUCTOR)'); # Test parameters
# my @unique = unique_elements @array;
#
# Return a sorted list of unique values out of all values passed in as
# parameters.
sub unique_elements
{
my %seen;
return sort grep { ! $seen{$_}++ } @_;
}
sub VARSTRUCTOR
{
##########################################################
# 1st parameter:
# Assign "show" to print variables and values or
# "clear" to clear variables. For security reasons, the
# default is clear.
# set up default action
my $action = 'clear';
# see if first arg is "show" or "clear"
if ( $_[0] =~ /^\s*(show|clear)\s*$/i )
{
shift; # ok, get rid of it
$action = lc $1;
}
# 2nd parameter:
# Comma-separated list of variables, subroutines, and
# labels, whose variables will be included or excluded.
# Labels must be of labeled blocks that are wrapped in
# braces. This parameter must begin with "I:" or "E:"
# (include or exclude).
#
# You can't include or exclude array elements, hash
# keys or hash values. Legal variables for this
# parameter begin with $, @, and %, followed by a
# string of word characters not beginning with a digit.
#
# The label and subroutine name lists must be enclosed
# in separate sets of parentheses, following the word
# "labels" or "subs". A comma after the closing
# parenthesis is necessary when another item in this
# parameter follows. Commas also must separate the
# labels and subroutine names within the parentheses.
# Within the code to be parsed, there must be nothing
# preceding the labels and the "sub"s on the
# same line except for optional spaces, and the
# subroutines and labeled blocks must end with the
# next "}" that is at the same level of indentation as
# the first character of the label or the "s" of "sub".
# Within the parameters, the "&" is optional before
# subroutine names and the ":" is optional after labels.
my $include = 0;
my $vars = '';
if ( $_[0] =~ /^\s([iIeE]):\s*(.*)$/)
{
shift; # get rid of it
$include = 1 if lc $1 eq 'i';
$vars = $2;
}
# 3rd parameter:
# Target file. Default is $0, indicating the file
# VarStructor is being run from.
# last arg is file name to read the source code from. defaults to
# using the currently-executing script ($0).
my $in_file_name = shift || $0;
##########################################################
my $file = do
{
open my $fh, $in_file_name
or die "opening '$in_file_name': $!";
local $/ = undef; # enter slurp mode
<$fh>;
};
# delete whole-line comments
$file =~ s/^\s*#.*$//mg;
### Prevent parsing of some quoted strings by deleting here
### docs. Rarely, a single quoted string would be mistaken for a
### variable if not in a here doc.
# Delete here docs with quoted identifiers
$file =~ s/<<\s*('|"|`)
([^\n]*?([^\\]|[^\\]\\\\))\1 # Match here doc identifier, which
# ends with an unescaped closing
# quote. Limitation: an even number
# of slashes greater than two at
# the end of the identifier would
# be wrongly interpreted as
# escaping the quote and the here
# doc value would probably not get
# deleted.
.*?\n\2\n//sgx;
# Delete here docs with unquoted identifiers
# (tkil) greediness will kill you here
$file =~ s/<<(\w+);.*?\n\1\n//sg;
# accumulators
my $subs = '';
my $labels = '';
my $out_vars = '';
my @all_vars;
my @hash_disp;
# Isolate subroutines to search, according to $vars
# look for subexpressions like: "subs ( my_sub_1, my_sub_2 )"
# remove it from $vars, then add each subroutine to output.
while ($vars =~ s/ subs \s* \( ( [^\)]+ ) \) \s* //x )
{
my $subs = $1;
foreach my $sub ( map quotemeta, split /,\s*/, $subs )
{
# find the subroutine in the file, save the definition.
$file =~ m! ( # entire expression in $1
^ (\s*) # save indent for later matching
sub \s+ $sub \s*# actual decl start
(?: \( [^\)]+ \) ) # skip prototypes
\s* \{ # opening brace
.*? # whatever (but note non-greedy)
^ \2 \} ) $ # look for brace at same indent
!xsm
or die "couldn't find definition of sub '$sub'";
# save the definition we just found
$subs .= $1;
}
}
# Isolate labeled blocks to search, according to $vars this time,
# look for: labels( ... ) and remove every match from$vars as we
# find them:
while ($vars =~ s/ labels \s* \( ( [^\)]+ ) \) \s* //x )
{
my $labels = $1;
foreach my $label ( map quotemeta, split /,\s*/, $labels )
{
$file =~ m! ( # whole expression ($1)
^ (\s*) # capture label indent ($2)
$label: \s*?
(^ \s*)? # capture loop indent, maybe ($3)
(?: do |
for(?:each)? \(.*?\) |
while \(.*?\) |
until \(.*?\) |
) \s*?
\{
.*? # actual block contents
^ ( \2 | \3 ) \} # closing brace at either label
# or loop indent level
!smx
or die "couldn't find label '$label'" .
" in '$in_file_name'";
# save it for later
$labels .= $1;
}
# Delete or include individual variables, according to $vars
while ($vars =~ s/([\$\@\%][^\d\W]\w*)//x)
{
my $this_var = $1;
if ( $include )
{
$out_vars .= "$this_var='';";
}
else
{
$file =~ s/\Q$this_var\E//g;
}
}
if ( $include )
{
$file = "$out_vars $subs $labels";
}
else
{
# (tkil) this looks completely bogus. WTH?
$file =~ s/\Q($subs|$labels)\E//;
}
# Find arrays. If not an array used in push, require an equals sign
# to avoid quoted email addresses that look like arrays.
while (($file =~ s/([^\\]|[^\\]\\\\)(\@[^\d\W]\w*)\s*=//)||
# Find scalars/array elements after ++ or --
($file =~ s/(?:[^\\]|[^\\]\\\\)(\+\+|--)\s*(\$[^\d\W]\w*(\[.*?\])?)//)||
# Find scalars/array elements before assignment operators, "++",
# "--", "." or ".="
($file =~ s/([^\\]|[^\\]\\\\)(\$[^\d\W]\w*(\[.*?\])?)\s*(=|\+=|-=|\*=|\/=|\%=|\*\*=|\+\+|--|\.)//)||
# Find arrays assigned to with push.
($file =~ s/push[^\w_]*([^\\]|[^\\]\\\\)(\@[^\d\W]\w*)//))
{
my $this_var = $2;
$this_var =~ s/^\$(.*)\[.*/\@$1/; # Convert element to its array
my $eval_var;
if ( $action eq 'clear' )
{
$eval_var = $this_var =~ /^\$/ ? "$this_var='';" : "$this_var=();";
}
else
{
# To do: print index numbers next to values
$eval_var = "\\$this_var = $this_var\\n";
}
push (@all_vars, $eval_var);
}
# Extract hashes
while (($file =~ s/([^\\]|[^\\]\\\\)\%([^\d\W]\w*)\s*=//)||
($file =~ s/([^\\]|[^\\]\\\\)\$([^\d\W]\w*)\{[^\n]*\}\s*=//)) {
my $this_hash = $2;
if ( $action eq 'clear' )
{
push @hash_disp, "\%$this_hash=();"
}
else
{
push @hash_disp, "print \"\\n\%$this_hash\\n\";" .
"foreach \$key (sort(keys \%$this_hash))" .
"{print \$key, '=', \$$this_hash\{\$key\}, \"\\n\";}"
}
}
my $all_vars = join '', unique_elements @all_vars;
if ( action eq 'show' )
{
$all_vars =~ s/.*/print"$&";/;
}
eval $all_vars;
my $hash_display = join '', unique_elements @hash_disp;
eval $hash_display;
}