#####################################
1:An Overview of Perl/Getting Started
#####################################

print "Howdy, world!\n";

######################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax
######################################################################

$phrase = "Howdy, world!\n";          # Set a variable.
print $phrase;                        # Print the variable.

####################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Singularities
####################################################################################

$answer = 42;                # an integer
$pi = 3.14159265;            # a "real" number
$avocados = 6.02e23;         # scientific notation
$pet = "Camel";              # string
$sign = "I love my $pet";    # string with interpolation
$cost = 'It costs $100';     # string without interpolation
$thence = $whence;           # another variable's value
$salsa = $moles * $avocados; # a gastrochemical expression
$exit = system("vi $file");  # numeric status of a command
$cwd = `pwd`;                # string output from a command

--------------

$ary = \@myarray;            # reference to a named array
$hsh = \%myhash;             # reference to a named hash
$sub = \&mysub;              # reference to a named subroutine

$ary = [1,2,3,4,5];          # reference to an unnamed array
$hsh = {Na => 19, Cl => 35}; # reference to an unnamed hash
$sub = sub { print $state }; # reference to an unnamed subroutine

$fido = new Camel "Amelia";  # ref to an object

--------------

$camels = '123';
print $camels + 1, "\n";

--------------

$fido = new Camel "Amelia";
if (not $fido) { die "dead camel"; }
$fido->saddle();

##########################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Pluralities/Arrays.
##########################################################################################

@home = ("couch", "chair", "table", "stove");

--------------

($potato, $lift, $tennis, $pipe) = @home;

--------------

($alpha,$omega) = ($omega,$alpha);

--------------

$home[0] = "couch";
$home[1] = "chair";
$home[2] = "table";
$home[3] = "stove";

##########################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Pluralities/Hashes.
##########################################################################################

%longday = ("Sun", "Sunday", "Mon", "Monday", "Tue", "Tuesday",
            "Wed", "Wednesday", "Thu", "Thursday", "Fri",
            "Friday", "Sat", "Saturday");

--------------

%longday = (
    "Sun" => "Sunday",
    "Mon" => "Monday",
    "Tue" => "Tuesday",
    "Wed" => "Wednesday",
    "Thu" => "Thursday",
    "Fri" => "Friday",
    "Sat" => "Saturday",
);

--------------

$wife{"Adam"} = "Eve";

###################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Complexities
###################################################################################

$wife{"Jacob"} = ("Leah", "Rachel", "Bilhah", "Zilpah");

--------------

$wife{"Jacob"} = ["Leah", "Rachel", "Bilhah", "Zilpah"];

--------------

$wife{"Jacob"}[0] = "Leah";
$wife{"Jacob"}[1] = "Rachel";
$wife{"Jacob"}[2] = "Bilhah";
$wife{"Jacob"}[3] = "Zilpah";

--------------

$kids_of_wife{"Jacob"} = {
    "Leah"   => ["Reuben", "Simeon", "Levi",
                 "Judah", "Issachar", "Zebulun"],
    "Rachel" => ["Joseph", "Benjamin"],
    "Bilhah" => ["Dan", "Naphtali"],
    "Zilpah" => ["Gad", "Asher"],
};

--------------

$kids_of_wife{"Jacob"}{"Leah"}[0]   = "Reuben";
$kids_of_wife{"Jacob"}{"Leah"}[1]   = "Simeon";
$kids_of_wife{"Jacob"}{"Leah"}[2]   = "Levi";
$kids_of_wife{"Jacob"}{"Leah"}[3]   = "Judah";
$kids_of_wife{"Jacob"}{"Leah"}[4]   = "Issachar";
$kids_of_wife{"Jacob"}{"Leah"}[5]   = "Zebulun";
$kids_of_wife{"Jacob"}{"Rachel"}[0] = "Joseph";
$kids_of_wife{"Jacob"}{"Rachel"}[1] = "Benjamin";
$kids_of_wife{"Jacob"}{"Bilhah"}[0] = "Dan";
$kids_of_wife{"Jacob"}{"Bilhah"}[1] = "Naphtali";
$kids_of_wife{"Jacob"}{"Zilpah"}[0] = "Gad";
$kids_of_wife{"Jacob"}{"Zilpah"}[1] = "Asher";

--------------

$fido = new Camel "Amelia";

###################################################################################
1:An Overview of Perl/Natural and Artificial Languages/Variable Syntax/Simplicities
###################################################################################

package Camel;

--------------

package Camel;
$fido = &fetch();

--------------

package Dog;
$fido = &fetch();

--------------

$fido = new Camel "Amelia";

--------------

$fido->saddle();

--------------

use Camel;

--------------

$fido = new Camel "Amelia";

--------------

use Some::Cool::Module;

--------------

use strict;

############################################################
1:An Overview of Perl/Natural and Artificial Languages/Verbs
############################################################

print "Adam's wife is $wife{'Adam'}.\n";

--------------

$e = exp(1);   # 2.718281828459 or thereabouts

########################################
1:An Overview of Perl/An Average Example
########################################

#!/usr/bin/perl

open(GRADES, "grades") or die "Can't open grades: $!\n";
while ($line = ) {
    ($student, $grade) = split(" ", $line);
    $grades{$student} .= $grade . " ";
}

foreach $student (sort keys %grades) {
    $scores = 0;
    $total = 0;    
    @grades = split(" ", $grades{$student});
    foreach $grade (@grades) {
        $total += $grade;
        $scores++;
    }
    $average = $total / $scores;
    print "$student: $grades{$student}\tAverage: $average\n";
}

#####################################################
1:An Overview of Perl/An Average Example/How to Do It
#####################################################

% perl -e 'print "Hello, world!\n";'

--------------

% perl gradation

--------------

#!/usr/bin/perl

--------------

% gradation

--------------

% ../bin/gradation

--------------

#!/bin/sh -- # perl, to stop looping
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
    if 0;

--------------

#!/usr/bin/perl -w

#################################
1:An Overview of Perl/Filehandles
#################################

open(SESAME, "filename")               # read from existing file
open(SESAME, "filename")              # create file and write to it
open(SESAME, ">>filename")             # append to existing file
open(SESAME, "| output-pipe-command")  # set up an output filter
open(SESAME, "input-pipe-command |")   # set up an input filter

--------------

print STDOUT "Enter a number: ";          # ask for a number
$number = ;                        # input the number
print STDOUT "The number is $number.\n";  # print the number

--------------

chop($number = );    # input number and remove newline

--------------

$number = ;          # input number
chop($number);              # remove newline

################################################
1:An Overview of Perl/Operators/String Operators
################################################

$a = 123;
$b = 456;
print $a + $b;     # prints 579
print $a . $b;     # prints 123456

--------------

$a = 123;
$b = 3;
print $a * $b;     # prints 369
print $a x $b;     # prints 123123123

--------------

print $a . ' is equal to ' . $b . ".\n";    # dot operator
print $a, ' is equal to ', $b, ".\n";       # list
print "$a is equal to $b.\n";               # interpolation

--------------

print "-" x $scrwid, "\n";

####################################################
1:An Overview of Perl/Operators/Assignment Operators
####################################################

$a = $b;
$a = $b + 5;
$a = $a * 3;

--------------

$a *= 3;

--------------

$line .= "\n";  # Append newline to $line.
$fill x= 80;    # Make string $fill into 80 repeats of itself.
$val ||= "2";   # Set $val to 2 if it isn't already "true".

--------------

$a = $b = $c = 0;

--------------

($temp -= 32) *= 5/9;

--------------

chop($number = );

##########################################################
1:An Overview of Perl/Operators/Unary Arithmetic Operators
##########################################################

$a = 5;        # $a is assigned 5
$b = ++$a;     # $b is assigned the incremented value of $a, 6
$c = $a--;     # $c is assigned 6, then $a is decremented to 5

#################################################
1:An Overview of Perl/Operators/Logical Operators
#################################################

open(GRADES, "grades") or die "Can't open file grades: $!\n";

########################################################
1:An Overview of Perl/Operators/Some File Test Operators
########################################################

-e "/usr/bin/perl" or warn "Perl is improperly installed\n";
-f "/vmlinuz" and print "I see you are a friend of Linus\n";

#######################################################
1:An Overview of Perl/Control Structures/What Is Truth?
#######################################################

0          # would become the string "0", so false.
1          # would become the string "1", so true.
10 - 10    # 10-10 is 0, would convert to string "0", so false.
0.00       # equals 0, would convert to string "0", so false.
"0"        # the string "0", so false.
""         # a null string, so false.
"0.00"     # the string "0.00", neither "" nor "0", so true!
"0.00" + 0 # the number 0 (coerced by the +), so false.
\$a        # a reference to $a, so true, even if $a is false.
undef()    # a function returning the undefined value, so false.

####################################################################################
1:An Overview of Perl/Control Structures/What Is Truth?/The if and unless statements
####################################################################################

if ($debug_level > 0) {
    # Something has gone wrong.  Tell the user.
    print "Debug: Danger, Will Robinson, danger!\n";
    print "Debug: Answer was '54', expected '42'.\n";
}

--------------

if ($city eq "New York") {
    print "New York is northeast of Washington, D.C.\n";
}
elsif ($city eq "Chicago") {
    print "Chicago is northwest of Washington, D.C.\n";
}
elsif ($city eq "Miami") {
    print "Miami is south of Washington, D.C.  And much warmer!\n";
}
else {
    print "I don't know where $city is, sorry.\n";
}

--------------

unless ($destination eq $home) {
    print "I'm not going home.\n";
}

######################################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/The while and until statements
######################################################################################################

while ($tickets_sold < 10000) {
    $available = 10000 - $tickets_sold;
    print "$available tickets are available.  How many would you like: ";
    $purchase = ;
    chomp($purchase);
    $tickets_sold += $purchase;
}

--------------

print "This show is sold out, please come back later.\n";

--------------

while (@ARGV) {
    process(shift @ARGV);
}

#########################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/The for statement
#########################################################################################

for ($sold = 0; $sold < 10000; $sold += $purchase) {
    $available = 10000 - $sold;
    print "$available tickets are available.  How many would you like: ";
    $purchase = ;
    chomp($purchase);
}

#############################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/The foreach statement
#############################################################################################

foreach $user (@users) {
    if (-f "$home{$user}/.nexrc") {
        print "$user is cool... they use a perl-aware vi!\n";
    }
}

--------------

foreach $key (sort keys %hash) {

###################################################################################################
1:An Overview of Perl/Control Structures/Iterative (Looping) Constructs/Breaking out: next and last
###################################################################################################

foreach $user (@users) {
    if ($user eq "root" or $user eq "lp") {
        next;
    }
    if ($user eq "special") {
        print "Found the special account.\n";
        # do some processing
        last;
    }
}

--------------

LINE: while ($line = 
) { last LINE if $line eq "\n"; # stop on first blank line next LINE if $line =~ /^#/; # skip comment lines # your ad here } ######################################### 1:An Overview of Perl/Regular Expressions ######################################### if (/Windows 95/) { print "Time to upgrade?\n" } -------------- s/Windows/Linux/; -------------- ($good, $bad, $ugly) = split(/,/, "vi,emacs,teco"); -------------- while ($line = ) { if ($line =~ /http:/) { print $line; } } -------------- while () { print if /http:/; } -------------- while () { print if /http:/; print if /ftp:/; print if /mailto:/; # What next? } ##################################################### 1:An Overview of Perl/Regular Expressions/Quantifiers ##################################################### $_ = "fred xxxxxxx barney"; s/x*//; ############################################################# 1:An Overview of Perl/Regular Expressions/Nailing Things Down ############################################################# /\bFred\b/ -------------- next LINE if $line =~ /^#/; ######################################################## 1:An Overview of Perl/Regular Expressions/Backreferences ######################################################## s/(\S+)\s+(\S+)/$2 $1/ ##################################### 1:An Overview of Perl/List Processing ##################################### @array = (1 + 2, 3 - 4, 5 * 6, 7 / 8); -------------- sort @dudes, @chicks, other(); -------------- print reverse sort map {lc} keys %hash; -------------- ($hour, $min, $sec, $ampm) = /(\d+):(\d+):(\d+) *(\w+)/; -------------- @hmsa = /(\d+):(\d+):(\d+) *(\w+)/; ##################################### 2:Bits and Pieces/Built-in Data Types ##################################### $x = $y; -------------- $x = $y + 1; ########################### 2:Bits and Pieces/Variables ########################### @days = 1 .. 7; ####################### 2:Bits and Pieces/Names ####################### $Santa::Helper::Reindeer::Rudolph::nose #################################### 2:Bits and Pieces/Names/Name Lookups #################################### $bert -------------- ${ some_expression() } ################################################ 2:Bits and Pieces/Scalar Values/Numeric literals ################################################ $x = 12345; # integer $x = 12345.67; # floating point $x = 6.02e23; # scientific notation $x = 4_294_967_296; # underline for legibility $x = 0377; # octal $x = 0xffff; # hexadecimal $x = 0b1100_0000; # binary ############################################### 2:Bits and Pieces/Scalar Values/String literals ############################################### $Price = '$100'; # not interpolated print "The price is $Price.\n"; # interpolated -------------- $days{'Feb'} -------------- $days{Feb} -------------- $days{'February 29th'} # Ok. $days{"February 29th"} # Also ok. "" doesn't have to interpolate. $days{ February 29th } # WRONG, produces parse error. -------------- @days{'Jan','Feb'} # Ok. @days{"Jan","Feb"} # Also ok. @days{ Jan, Feb } # Kinda wrong (breaks under use strict) -------------- print "\n"; # Ok, print a newline. print \n ; # WRONG, no interpolative context. #################################################### 2:Bits and Pieces/Scalar Values/Pick your own quotes #################################################### $single = q!I said, "You said, 'She said it.'"!; $double = qq(Can't we get some "good" $variable?); $chunk_of_code = q { if ($condition) { print "Gotcha!"; } }; -------------- tr (a-f) [A-F]; -------------- s {foo} # Replace foo {bar}; # with bar. tr [a-f] # Translate lowercase hex [A-F]; # to uppercase hex ################################################################ 2:Bits and Pieces/Scalar Values/Or leave the quotes out entirely ################################################################ @days = (Mon,Tue,Wed,Thu,Fri); print STDOUT hello, ' ', world, "\n"; -------------- @days = qw(Mon Tue Wed Thu Fri); print STDOUT "hello world\n"; -------------- use strict 'subs'; -------------- no strict 'subs'; -------------- "${verb}able" $days{Feb} ########################################################## 2:Bits and Pieces/Scalar Values/Interpolating array values ########################################################## $temp = join( $", @ARGV ); print $temp; print "@ARGV"; ################################################ 2:Bits and Pieces/Scalar Values/"Here" documents ################################################ print < 0xff0000, green => 0x00ff00, blue => 0x0000ff, ); -------------- $rec = { NAME => 'John Smith', RANK => 'Captain', SERNO => '951413', }; -------------- $field = radio_group( NAME => 'animals', VALUES => ['camel', 'llama', 'ram', 'wolf'], DEFAULT => 'camel', LINEBREAK => 'true', LABELS => \%animal_names, ); ########################################### 2:Bits and Pieces/Typeglobs and Filehandles ########################################### $fh = *STDOUT; -------------- $fh = \*STDOUT; -------------- sub newopen { my $path = shift; local *FH; # not my() nor our() open(FH, $path) or return undef; return *FH; # not \*FH! } $fh = newopen('/etc/passwd'); -------------- *foo = *bar; -------------- *foo = \$bar; -------------- local *Here::blue = \$There::green; ################################################################### 2:Bits and Pieces/Input Operators/Command input (backtick) operator ################################################################### $info = `finger $user`; -------------- $perl_info = qx(ps $$); # that's Perl's $$ $shell_info = qx'ps $$'; # that's the shell's $$ ############################################################# 2:Bits and Pieces/Input Operators/Line input (angle) operator ############################################################# while (defined($_ = )) { print $_; } # the longest way while ($_ = ) { print; } # explicitly to $_ while () { print; } # the short way for (;;) { print; } # while loop in disguise print $_ while defined($_ = ); # long statement modifier print while $_ = ; # explicitly to $_ print while ; # short statement modifier -------------- while ( && ) { ... } # WRONG: discards both inputs if () { print; } # WRONG: prints old value of $_ if ($_ = ) { print; } # suboptimal: doesn't test defined if (defined($_ = )) { print; } # best -------------- while (local $_ = ) { print; } # use local $_ -------------- while (my $line = ) { print $line; } # now private -------------- $one_line = ; # Get first line. @all_lines = ; # Get the rest of the lines. -------------- while (<>) { ... # code for each line } -------------- @ARGV = ('-') unless @ARGV; # assume STDIN iff empty while (@ARGV) { $ARGV = shift @ARGV; # shorten @ARGV each time if (!open(ARGV, $ARGV)) { warn "Can't open $ARGV: $!\n"; next; } while () { ... # code for each line } } -------------- # default to README file if no args given @ARGV = ("README") unless @ARGV; -------------- while (@ARGV and $ARGV[0] =~ /^-/) { $_ = shift; last if /^--$/; if (/^-D(.*)/) { $debug = $1 } if (/^-v/) { $verbose++ } ... # other switches } while (<>) { ... # code for each line } -------------- $fh = \*STDIN; $line = <$fh>; -------------- open($fh, "; ############################################################ 2:Bits and Pieces/Input Operators/Filename globbing operator ############################################################ @files = <*.xml>; -------------- @files = glob("*.xml"); -------------- while (glob "*.c") { chmod 0644, $_; } -------------- while (<*.c>) { chmod 0644, $_; } -------------- chmod 0644, <*.c>; -------------- ($file) = ; # list context -------------- $file = ; # scalar context -------------- @files = <$dir/*.[ch]>; # Works, but avoid. @files = glob("$dir/*.[ch]"); # Call glob as function. @files = glob $some_pattern; # Call glob as operator. ############################ 3:Unary and Binary Operators ############################ ! $x # a unary operator $x * $y # a binary operator $x ? $y : $z # a trinary operator print $x, $y, $z # a list operator -------------- 2 + 3 * 4 # yields 14, not 20 -------------- 2 * 3 * 4 # means (2 * 3) * 4, left associative 2 ** 3 ** 4 # means 2 ** (3 ** 4), right associative 2 != 3 != 4 # illegal, non-associative ################################################################ 3:Unary and Binary Operators/Terms and List Operators (Leftward) ################################################################ chdir $foo || die; # (chdir $foo) || die chdir($foo) || die; # (chdir $foo) || die chdir ($foo) || die; # (chdir $foo) || die chdir +($foo) || die; # (chdir $foo) || die -------------- chdir $foo * 20; # chdir ($foo * 20) chdir($foo) * 20; # (chdir $foo) * 20 chdir ($foo) * 20; # (chdir $foo) * 20 chdir +($foo) * 20; # chdir ($foo * 20) -------------- rand 10 * 20; # rand (10 * 20) rand(10) * 20; # (rand 10) * 20 rand (10) * 20; # (rand 10) * 20 rand +(10) * 20; # rand (10 * 20) -------------- @ary = (1, 3, sort 4, 2); print @ary; # prints 1324 -------------- # These evaluate exit before doing the print: print($foo, exit); # Obviously not what you want. print $foo, exit; # Nor this. # These do the print before evaluating exit: (print $foo), exit; # This is what you want. print($foo), exit; # Or this. print ($foo), exit; # Or even this. -------------- print ($foo & 255) + 1, "\n"; # prints ($foo & 255) ############################################### 3:Unary and Binary Operators/The Arrow Operator ############################################### $aref->[42] # an array dereference $href->{"corned beef"} # a hash dereference $sref->(1,2,3) # a subroutine dereference -------------- $yogi = Bear->new("Yogi"); # a class method call $yogi->swipe($picnic); # an object method call ############################################################ 3:Unary and Binary Operators/Autoincrement and Autodecrement ############################################################ print ++($foo = '99'); # prints '100' print ++($foo = 'a0'); # prints 'a1' print ++($foo = 'Az'); # prints 'Ba' print ++($foo = 'zz'); # prints 'aaa' ############################################## 3:Unary and Binary Operators/Binding Operators ############################################## $string !~ /pattern/ not $string =~ /pattern/ -------------- if ( ($k,$v) = $string =~ m/(\w+)=(\w*)/ ) { print "KEY $k VALUE $v\n"; } ##################################################### 3:Unary and Binary Operators/Multiplicative Operators ##################################################### print '-' x 80; # print row of dashes print "\t" x ($tab/8), ' ' x ($tab%8); # tab over -------------- @ones = (1) x 80; # a list of 80 1's @ones = (5) x @ones; # set all elements to 5 -------------- @keys = qw(perls before swine); @hash{@keys} = ("") x @keys; -------------- $hash{perls} = ""; $hash{before} = ""; $hash{swine} = ""; ############################################### 3:Unary and Binary Operators/Additive Operators ############################################### $almost = "Fred" . "Flintstone"; # returns FredFlintstone -------------- $fullname = "$firstname $lastname"; ############################################ 3:Unary and Binary Operators/Shift Operators ############################################ 1 << 4; # returns 16 32 >> 4; # returns 2 ################################################################ 3:Unary and Binary Operators/Named Unary and File Test Operators ################################################################ sleep 4 | 3; -------------- (sleep 4) | 3; -------------- print 4 | 3; -------------- print (4 | 3); -------------- next if length < 80; -------------- next if length() < 80; next if (length) < 80; next if 80 > length; next unless length >= 80; -------------- while (<>) { chomp; next unless -f $_; # ignore "special" files ... } -------------- next unless -f $file && -T $file; -------------- print "Can do.\n" if -r $a || -w _ || -x _; stat($filename); print "Readable\n" if -r _; print "Writable\n" if -w _; print "Executable\n" if -x _; print "Setuid\n" if -u _; print "Setgid\n" if -g _; print "Sticky\n" if -k _; print "Text\n" if -T _; print "Binary\n" if -B _; -------------- next unless -M $file > .5; # files older than 12 hours &newfile if -M $file < 0; # file is newer than process &mailwarning if int(-A) == 90; # file ($_) accessed 90 days ago today -------------- $^T = time; ############################################## 3:Unary and Binary Operators/Bitwise Operators ############################################## "123.45" & "234.56" -------------- "020.44" -------------- "123.45" & 234.56 -------------- 123.45 & 234.56 -------------- 123 & 234 -------------- if ( "fred" & "\1\2\3\4" ) { ... } -------------- if ( ("fred" & "\1\2\3\4") =~ /[^\0]/ ) { ... } ###################################################################### 3:Unary and Binary Operators/C-style Logical (Short Circuit) Operators ###################################################################### open(FILE, "somefile") || die "Can't open somefile: $!\n"; -------------- $home = $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7] || die "You're homeless!\n"; -------------- @a = @b || @c; # This doesn't do the right thing @a = scalar(@b) || @c; # because it really means this. @a = @b ? @b : @c; # This works fine, though. ########################################### 3:Unary and Binary Operators/Range Operator ########################################### if (101 .. 200) { print; } # print 2nd hundred lines next line if (1 .. /^$/); # skip header lines s/^/> / if (/^$/ .. eof()); # quote body -------------- for (101 .. 200) { print; } # prints 101102...199200 @foo = @foo[0 .. $#foo]; # an expensive no-op @foo = @foo[ -5 .. -1]; # slice last 5 items -------------- @alphabet = ('A' .. 'Z'); -------------- $hexdigit = (0 .. 9, 'a' .. 'f')[$num & 15]; -------------- @z2 = ('01' .. '31'); print $z2[$mday]; -------------- @combos = ('aa' .. 'zz'); -------------- @bigcombos = ('aaaaaa' .. 'zzzzzz'); ################################################# 3:Unary and Binary Operators/Conditional Operator ################################################# $a = $ok ? $b : $c; # get a scalar @a = $ok ? @b : @c; # get an array $a = $ok ? @b : @c; # get a count of an array's elements -------------- printf "I have %d camel%s.\n", $n, $n == 1 ? "" : "s"; -------------- $leapyear = $year % 4 == 0 ? $year % 100 == 0 ? $year % 400 == 0 ? 1 : 0 : 1 : 0; -------------- $leapyear = $year % 4 ? 0 : $year % 100 ? 1 : $year % 400 ? 0 : 1; -------------- $leapyear = $year % 4 ? 0 : $year % 100 ? 1 : $year % 400 ? 0 : 1; -------------- printf "Yes, I like my %s book!\n", $i18n eq "french" ? "chameau" : $i18n eq "german" ? "Kamel" : $i18n eq "japanese" ? "\x{99F1}\x{99DD}" : "camel" -------------- ($a_or_b ? $a : $b) = $c; # sets either $a or $b to equal $c -------------- $a % 2 ? $a += 10 : $a += 2 # WRONG -------------- (($a % 2) ? ($a += 10) : $a) += 2 ################################################# 3:Unary and Binary Operators/Assignment Operators ################################################# $var[$a++] += $value; # $a is incremented once $var[$a++] = $var[$a++] + $value; # $a is incremented twice -------------- ($tmp = $global) += $constant; -------------- $tmp = $global + $constant; -------------- ($a += 2) *= 3; -------------- $a += 2; $a *= 3; -------------- ($new = $old) =~ s/foo/bar/g; -------------- $a = $b = $c = 0; -------------- while (($key, $value) = each %gloss) { ... } next unless ($dev, $ino, $mode) = stat $file; ############################################ 3:Unary and Binary Operators/Comma Operators ############################################ $a = (1, 3); -------------- @a = (1, 3); -------------- atan2(1, 3); ########################################################## 3:Unary and Binary Operators/Logical and, or, not, and xor ########################################################## unlink "alpha", "beta", "gamma" or gripe(), next LINE; -------------- unlink("alpha", "beta", "gamma") || (gripe(), next LINE); -------------- $xyz = $x || $y || $z; -------------- $xyz = $x or $y or $z; # WRONG -------------- $xyz = ( $x or $y or $z ); ########################################################## 3:Unary and Binary Operators/C Operators Missing from Perl ########################################################## $ref_to_var = \$var; ############################################### 4:Statements and Declarations/Simple Statements ############################################### $trash->take('out') if $you_love_me; shutup() unless $you_want_me_to_leave; -------------- $expression++ while -e "$file$expression"; kiss('me') until $I_die; -------------- s/java/perl/ for @resumes; print "field: $_\n" foreach split /:/, $dataline; -------------- do { $line = ; ... } until $line eq ".\n"; ################################################# 4:Statements and Declarations/Compound Statements ################################################# unless (open(FOO, $foo)) { die "Can't open $foo: $!" } if (!open(FOO, $foo)) { die "Can't open $foo: $!" } die "Can't open $foo: $!" unless open(FOO, $foo); die "Can't open $foo: $!" if !open(FOO, $foo); open(FOO, $foo) || die "Can't open $foo: $!"; open FOO, $foo or die "Can't open $foo: $!"; -------------- chdir $dir or die "chdir $dir: $!"; open FOO, $file or die "open $file: $!"; @lines = or die "$file is empty?"; close FOO or die "close $file: $!"; ###################################################### 4:Statements and Declarations/If and Unless Statements ###################################################### unless ($x == 1) ... -------------- if ($x != 1) ... -------------- if (!($x == 1)) ... -------------- if ((my $color = ) =~ /red/i) { $value = 0xff0000; } elsif ($color =~ /green/i) { $value = 0x00ff00; } elsif ($color =~ /blue/i) { $value = 0x0000ff; } else { warn "unknown RGB component `$color', using black instead\n"; $value = 0x000000; } ######################################################################## 4:Statements and Declarations/Loop Statements/While and Until Statements ######################################################################## while (my $line = ) { $line = lc $line; } continue { print $line; # still visible } # $line now out of scope here ####################################################### 4:Statements and Declarations/Loop Statements/For Loops ####################################################### LABEL: for (my $i = 1; $i <= 10; $i++) { ... } -------------- { my $i = 1; LABEL: while ($i <= 10) { ... } continue { $i++; } } -------------- for ($i = 0, $bit = 0; $i < 32; $i++, $bit <<= 1) { print "Bit $i is set\n" if $mask & $bit; } # the values in $i and $bit persist past the loop -------------- for (my ($i, $bit) = (0, 1); $i < 32; $i++, $bit <<= 1) { print "Bit $i is set\n" if $mask & $bit; } # loop's versions of $i and $bit now out of scope -------------- $on_a_tty = -t STDIN && -t STDOUT; sub prompt { print "yes? " if $on_a_tty } for ( prompt(); ; prompt() ) { # do something } -------------- for (;;) { ... } -------------- while (1) { ... } ########################################################### 4:Statements and Declarations/Loop Statements/Foreach Loops ########################################################### $sum = 0; foreach $value (@array) { $sum += $value } for $count (10,9,8,7,6,5,4,3,2,1,'BOOM') { # do a countdown print "$count\n"; sleep(1); } for (reverse 'BOOM', 1 .. 10) { # same thing print "$_\n"; sleep(1); } for $field (split /:/, $data) { # any LIST expression print "Field contains: `$field'\n"; } foreach $key (sort keys %hash) { print "$key => $hash{$key}\n"; } -------------- foreach $pay (@salaries) { # grant 8% raises $pay *= 1.08; } for (@christmas, @easter) { # change menu s/ham/turkey/; } s/ham/turkey/ for @christmas, @easter; # same thing for ($scalar, @array, values %hash) { s/^\s+//; # strip leading whitespace s/\s+$//; # strip trailing whitespace } -------------- for my $i (1 .. 10) { ... } # $i always lexical for our $Tick (1 .. 10) { ... } # $Tick always global -------------- for ($i = 0; $i < @ary1; $i++) { for ($j = 0; $j < @ary2; $j++) { if ($ary1[$i] > $ary2[$j]) { last; # Can't go to outer loop. :-( } $ary1[$i] += $ary2[$j]; } # this is where that last takes me } -------------- WID: foreach $this (@ary1) { JET: foreach $that (@ary2) { next WID if $this > $that; $this += $that; } } ########################################################## 4:Statements and Declarations/Loop Statements/Loop Control ########################################################## next LINE if /^#/; # discard comments -------------- LINE: while () { last LINE if /^$/; # exit when done with mail header ... } -------------- LINE: while () { next LINE if /^#/; # skip comments next LINE if /^$/; # skip blank lines ... } continue { $count++; } -------------- while (<>) { chomp; if (s/\\$//) { $_ .= <>; redo unless eof; # don't read past each file's eof } # now process $_ } -------------- LINE: while (defined($line = )) { chomp($line); if ($line =~ s/\\$//) { $line .= ; redo LINE unless eof(ARGV); } # now process $line } -------------- ARG: while (@ARGV && $ARGV[0] =~ s/^-(?=.)//) { OPT: for (shift @ARGV) { m/^$/ && do { next ARG; }; m/^-$/ && do { last ARG; }; s/^d// && do { $Debug_Level++; redo OPT; }; s/^l// && do { $Generate_Listing++; redo OPT; }; s/^i(.*)// && do { $In_Place = $1 || ".bak"; next ARG; }; say_usage("Unknown option: $_"); } } -------------- open FILE, $file or warn "Can't open $file: $!\n", next FILE; # WRONG -------------- open FILE, $file or warn("Can't open $file: $!\n"), next FILE; # okay -------------- unless (open FILE, $file) { warn "Can't open $file: $!\n"; next FILE; } ######################################### 4:Statements and Declarations/Bare Blocks ######################################### if (/pattern/) {{ last if /alpha/; last if /beta/; last if /gamma/; # do something here only if still in if() }} -------------- do {{ next if $x == $y; # do something here }} until $x++ > $z; -------------- { do { last if $x = $y ** 2; # do something here } while $x++ <= $z; } -------------- DO_LAST: { do { DO_NEXT: { next DO_NEXT if $x == $y; last DO_LAST if $x = $y ** 2; # do something here } } while $x++ <= $z; } -------------- for (;;) { next if $x == $y; last if $x = $y ** 2; # do something here last unless $x++ <= $z; } ######################################################### 4:Statements and Declarations/Bare Blocks/Case Structures ######################################################### SWITCH: { if (/^abc/) { $abc = 1; last SWITCH; } if (/^def/) { $def = 1; last SWITCH; } if (/^xyz/) { $xyz = 1; last SWITCH; } $nothing = 1; } -------------- SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1; } -------------- SWITCH: { /^abc/ && do { $abc = 1; last SWITCH; }; /^def/ && do { $def = 1; last SWITCH; }; /^xyz/ && do { $xyz = 1; last SWITCH; }; $nothing = 1; } -------------- if (/^abc/) { $abc = 1 } elsif (/^def/) { $def = 1 } elsif (/^xyz/) { $xyz = 1 } else { $nothing = 1 } -------------- for ($very_nasty_long_name[$i++][$j++]->method()) { /this pattern/ and do { push @flags, '-e'; last; }; /that one/ and do { push @flags, '-h'; last; }; /something else/ and do { last; }; die "unknown value: `$_'"; } -------------- for ($user_color_preference) { $value = /red/ ? 0xFF0000 : /green/ ? 0x00FF00 : /blue/ ? 0x0000FF : 0x000000 ; # black if all fail } -------------- %color_map = ( azure => 0xF0FFFF, chartreuse => 0x7FFF00, lavender => 0xE6E6FA, magenta => 0xFF00FF, turquoise => 0x40E0D0, ); -------------- $value = $color_map{ lc $user_color_preference } || 0x000000; ################################## 4:Statements and Declarations/Goto ################################## goto(("FOO", "BAR", "GLARCH")[$i]); # hope 0 <= i < 3 @loop_label = qw/FOO BAR GLARCH/; goto $loop_label[rand @loop_label]; # random teleport ################################################# 4:Statements and Declarations/Global Declarations ################################################# sub count (@); # Compiler now knows how to call count(). my $x; # Compiler now knows about lexical variable. $x = count(3,2,1); # Compiler can validate function call. sub count (@) { @_ } # Compiler now knows what count() means. -------------- sub myname; $me = myname $0 or die "can't get myname"; -------------- sub myname ($); $me = myname $0 || die "can't get myname"; ############################################################################## 4:Statements and Declarations/Scoped Declarations/Scoped Variable Declarations ############################################################################## my $nose; our $House; local $TV_channel; -------------- my ($nose, @eyes, %teeth); our ($House, @Autos, %Kids); local (*Spouse, $phone{HOME}); -------------- my ($foo) = ; my @array = ; -------------- my $foo = ; -------------- my $foo, $bar = 1; # WRONG -------------- my $foo; $bar = 1; -------------- sub check_warehouse { for my $widget (our @Current_Inventory) { print "I have a $widget in stock today.\n"; } } ################################################################################### 4:Statements and Declarations/Scoped Declarations/Lexically Scoped Variables: C ################################################################################### my $name = "fred"; my @stuff = ("car", "house", "club"); my ($vehicle, $home, $tool) = @stuff; -------------- { my $state = 0; sub on { $state = 1 } sub off { $state = 0 } sub toggle { $state = !$state } } -------------- my $x = $x; ############################################################################################## 4:Statements and Declarations/Scoped Declarations/Lexically Scoped Global Declarations: C ############################################################################################## sub check_warehouse { our @Current_Inventory; my $widget; foreach $widget (@Current_Inventory) { print "I have a $widget in stock today.\n"; } } -------------- our $PROGRAM_NAME = "waiter"; { our $PROGRAM_NAME = "server"; # Code called here sees "server". ... } # Code executed below still sees "server". -------------- my $i = 10; { my $i = 99; ... } # Code compiled below sees outer variable. local $PROGRAM_NAME = "waiter"; { local $PROGRAM_NAME = "server"; # Code called here sees "server". ... } # Code executed below sees "waiter" again. -------------- { local our @Current_Inventory = qw(bananas); check_warehouse(); # no, we haven't no bananas :-) } ######################################################################################## 4:Statements and Declarations/Scoped Declarations/Dynamically Scoped Variables: C ######################################################################################## { local $var = $newvalue; some_func(); ... } -------------- { $oldvalue = $var; $var = $newvalue; some_func(); ... } continue { $var = $oldvalue; } -------------- # WARNING: Changes are temporary to this dynamic scope. local $Some_Global = $Some_Global; ##################################### 4:Statements and Declarations/Pragmas ##################################### use warnings; use strict; use integer; use bytes; use constant pi => ( 4 * atan2(1,1) ); ########################################################## 4:Statements and Declarations/Pragmas/Controlling Warnings ########################################################## use warnings; # Enable warnings from here till end of file. ... { no warnings; # Disable warnings through end of block. ... } # Warnings are automatically enabled again here. -------------- { local $^W = 0; ... } #################################################################### 4:Statements and Declarations/Pragmas/Controlling the Use of Globals #################################################################### use strict 'vars'; -------------- no strict 'vars' ################## 5:Pattern Matching ################## match( $string, $pattern ); subst( $string, $pattern, $replacement ); ################################################## 5:Pattern Matching/The Regular Expression Bestiary ################################################## /Frodo/ -------------- /Frodo|Pippin|Merry|Sam/ -------------- /(Frodo|Drogo|Bilbo) Baggins/ -------------- /(Frod|Drog|Bilb)o Baggins/ -------------- /(bar){3}/ ############################################# 5:Pattern Matching/Pattern Matching Operators ############################################# $foo = "bar"; /$foo$/; -------------- /bar$/; -------------- print "matches" if $somestring =~ $somepattern; -------------- print "matches" if $somestring =~ m/$somepattern/; -------------- $haystack =~ m/needle/ # match a simple pattern $haystack =~ /needle/ # same thing $italiano =~ s/butter/olive oil/ # a healthy substitution $rotate13 =~ tr/a-zA-Z/n-za-mN-ZA-M/ # easy encryption (to break) -------------- /new life/ and # search in $_ and (if found) /new civilizations/ # boldly search $_ again s/sugar/aspartame/ # substitute a substitute into $_ tr/ATCG/TAGC/ # complement the DNA stranded in $_ -------------- "onshore" =~ s/on/off/; # WRONG: compile-time error -------------- if ((lc $magic_hat->fetch_contents->as_string) =~ /rabbit/) { print "Nyaa, what's up doc?\n"; } else { print "That trick never works!\n"; } -------------- if ($song !~ /words/) { print qq/"$song" appears to be a song without words.\n/; } -------------- $path =~ s#/tmp#/var/tmp/scratch#; if ($dir =~ m[/bin]) { print "No binary directories please.\n"; } -------------- s(egg); s{larva}{pupa}; s[pupa]/imago/; -------------- s (egg) ; s {larva} {pupa}; s [pupa] /imago/; -------------- "hot cross buns" =~ /cross/; print "Matched: <$`> $& <$'>\n"; # Matched: cross < buns> print "Left: <$`>\n"; # Left: print "Match: <$&>\n"; # Match: print "Right: <$'>\n"; # Right: < buns> -------------- $_ = "Bilbo Baggins's birthday is September 22"; /(.*)'s birthday is (.*)/; print "Person: $1\n"; print "Date: $2\n"; ############################################################### 5:Pattern Matching/Pattern Matching Operators/Pattern Modifiers ############################################################### m/\w+:(\s+\w+)\s*\d+/; # A word, colon, space, word, space, digits. m/\w+: (\s+ \w+) \s* \d+/x; # A word, colon, space, word, space, digits. m{ \w+: # Match a word and a colon. ( # (begin group) \s+ # Match one or more spaces. \w+ # Match another word. ) # (end group) \s* # Match zero or more spaces. \d+ # Match some digits }x; -------------- # Find duplicate words in paragraphs, possibly spanning line boundaries. # Use /x for space and comments, /i to match the both `is' # in "Is is this ok?", and use /g to find all dups. $/ = ""; # paragrep mode while (<>) { while ( m{ \b # start at a word boundary (\w\S+) # find a wordish chunk ( \s+ # separated by some whitespace \1 # and that chunk again ) + # repeat ad lib \b # until another word boundary }xig ) { print "dup word '$1' at paragraph $.\n"; } } ######################################################################### 5:Pattern Matching/Pattern Matching Operators/The m// Operator (Matching) ######################################################################### if ($shire =~ m/Baggins/) { ... } # search for Baggins in $shire if ($shire =~ /Baggins/) { ... } # search for Baggins in $shire if ( m#Baggins# ) { ... } # search right here in $_ if ( /Baggins/ ) { ... } # search right here in $_ -------------- if (($key,$value) = /(\w+): (.*)/) { ... } -------------- if (@perls = $paragraph =~ /perl/gi) { printf "Perl mentioned %d times.\n", scalar @perls; } -------------- $string = "password=xyzzy verbose=9 score=0"; -------------- %hash = (password => "xyzzy", verbose => 9, score => 0); -------------- %hash = $string =~ /(\w+)=(\w+)/g; -------------- open DICT, "/usr/dict/words" or die "Can't open words: $!\n"; while () { $first = $1 if ?(^neur.*)?; $last = $1 if /(^neur.*)/; } print $first,"\n"; # prints "neurad" print $last,"\n"; # prints "neurypnology" ############################################################################## 5:Pattern Matching/Pattern Matching Operators/The s/// Operator (Substitution) ############################################################################## $lotr = $hobbit; # Just copy The Hobbit $lotr =~ s/Bilbo/Frodo/g; # and write a sequel the easy way. -------------- if ($lotr =~ s/Bilbo/Frodo/) { print "Successfully wrote sequel." } $change_count = $lotr =~ s/Bilbo/Frodo/g; -------------- s/revision|version|release/\u$&/g; # Use | to mean "or" in a pattern -------------- s/version ([0-9.]+)/the $Names{$1} release/g; -------------- s{ version \s+ ( [0-9.]+ ) }{ $Names{$1} ? "the $Names{$1} release" : $& }xge; ########################################################################################################### 5:Pattern Matching/Pattern Matching Operators/The s/// Operator (Substitution)/Modifying strings en passant ########################################################################################################### $lotr = $hobbit; $lotr =~ s/Bilbo/Frodo/g; -------------- ($lotr = $hobbit) =~ s/Bilbo/Frodo/g; -------------- for (@chapters) { s/Bilbo/Frodo/g } # Do substitutions chapter by chapter. s/Bilbo/Frodo/g for @chapters; # Same thing. -------------- @oldhues = ('bluebird', 'bluegrass', 'bluefish', 'the blues'); for (@newhues = @oldhues) { s/blue/red/ } print "@newhues\n"; # prints: redbird redgrass redfish the reds -------------- for ($string) { s/^\s+//; # discard leading whitespace s/\s+$//; # discard trailing whitespace s/\s+/ /g; # collapse internal whitespace } -------------- $string = join(" ", split " ", $string); -------------- for ($newshow = $oldshow) { s/Fred/Homer/g; s/Wilma/Marge/g; s/Pebbles/Lisa/g; s/Dino/Bart/g; } ################################################################################################################################## 5:Pattern Matching/Pattern Matching Operators/The s/// Operator (Substitution)/When a Global Substitution Just Isn't Global Enough ################################################################################################################################## # put commas in the right places in an integer 1 while s/(\d)(\d\d\d)(?!\d)/$1,$2/; # expand tabs to 8-column spacing 1 while s/\t+/' ' x (length($&)*8 - length($`)%8)/e; # remove (nested (even deeply nested (like this))) comments 1 while s/\([^()]*\)//g; # remove duplicate words (and triplicate (and quadruplicate...)) 1 while s/\b(\w+) \1\b/$1/gi; ################################################################################## 5:Pattern Matching/Pattern Matching Operators/The tr/// Operator (Transliteration) ################################################################################## $message =~ tr/A-Za-z/N-ZA-Mn-za-m/; # rot13 encryption. -------------- tr/aeiou/!/; # change any vowel into a ! tr{/\\\r\n\b\f. }{_}; # change strange chars into an underscore tr/A-Z/a-z/ for @ARGV; # canonicalize to lower case ASCII $count = ($para =~ tr/\n//); # count the newlines in $para $count = tr/0-9//; # count the digits in $_ $word =~ tr/a-zA-Z//s; # bookkeeper -> bokeper tr/@$%*//d; # delete any of those tr#A-Za-z0-9+/##cd; # remove non-base64 chars # change en passant ($HOST = $host) =~ tr/a-z/A-Z/; $pathname =~ tr/a-zA-Z/_/cs; # change non-(ASCII)alphas to single underbar tr [\200-\377] [\000-\177]; # strip 8th bit, bytewise -------------- tr/AAA/XYZ/ -------------- $count = eval "tr/$oldlist/$newlist/"; die if $@; # propagates exception from illegal eval contents ################################################# 5:Pattern Matching/Metacharacters and Metasymbols ################################################# \ | ( ) [ { ^ $ * + ? . ###################################################################### 5:Pattern Matching/Metacharacters and Metasymbols/Wildcard Metasymbols ###################################################################### if ($pathname =~ /\.(.)\z/s) { print "Ends in $1\n"; } -------------- use utf8; use charnames qw/:full/; $BWV[887] = "G\N{MUSIC SHARP SIGN} minor"; ($note, $black, $mode) = $BWV[887] =~ /^([A-G])(.)\s+(\S+)/; print "That's lookin' sharp!\n" if $black eq chr(9839); ########################################################################### 5:Pattern Matching/Character Classes/Classic Perl Character Class Shortcuts ########################################################################### if ($var =~ /\D/) { warn "contains non-digit" } if ($var =~ /[^\w\s.]/) { warn "contains non-(word, space, dot)" } ####################################################### 5:Pattern Matching/Character Classes/Unicode Properties ####################################################### if ($var =~ /^\p{IsAlpha}+$/) { print "all alphabetic" } if ($var =~ s/[\p{Zl}\p{Zp}]/\n/g) { print "fixed newline wannabes" } -------------- perl -MConfig -le 'print $Config{privlib}' ################################################################################ 5:Pattern Matching/Character Classes/Unicode Properties/Unicode block properties ################################################################################ print "It's Greek to me!\n" if chr(931) =~ /\p{InGreek}/; ############################################################################################## 5:Pattern Matching/Character Classes/Unicode Properties/Defining your own character properties ############################################################################################## sub InKana { return <<'END'; 3040 309F 30A0 30FF END } -------------- sub InKana { return <<'END'; +utf8::InHiragana +utf8::InKatakana END } -------------- sub IsKana { return <<'END'; +utf8::InHiragana +utf8::InKatakana -utf8::IsCn END } -------------- sub IsNotKana { return <<'END'; !utf8::InHiragana -utf8::InKatakana +utf8::IsCn END } ################################################################## 5:Pattern Matching/Character Classes/POSIX-Style Character Classes ################################################################## 42 =~ /^[:digit:]$/ # WRONG -------------- 42 =~ /^[[:digit:]]+$/ ############################## 5:Pattern Matching/Quantifiers ############################## "exasperate" =~ /e(.*)e/ # $1 now "xasperat" -------------- "exasperate" =~ /e(.*?)e/ # $1 now "xasp" -------------- "exasperate" =~ /.*e(.*?)e/ # $1 now "rat" ###################################################################### 5:Pattern Matching/Positions/Beginnings: The C<\A> and C<^> Assertions ###################################################################### /\Abar/ # Matches "bar" and "barstool" /^bar/ # Matches "bar" and "barstool" /^bar/m # Matches "bar" and "barstool" and "sand\nbar" -------------- s/^\s+//gm; # Trim leading whitespace on each line $total++ while /^./mg; # Count nonblank lines ########################################################################### 5:Pattern Matching/Positions/Endings: The C<\z>, C<\Z>, and C<$> Assertions ########################################################################### /bot\z/ # Matches "robot" /bot\Z/ # Matches "robot" and "abbot\n" /bot$/ # Matches "robot" and "abbot\n" /bot$/m # Matches "robot" and "abbot\n" and "robot\nrules" /^robot$/ # Matches "robot" and "robot\n" /^robot$/m # Matches "robot" and "robot\n" and "this\nrobot\n" /\Arobot\Z/ # Matches "robot" and "robot\n" /\Arobot\z/ # Matches only "robot" -- but why didn't you use eq? -------------- s/\s*$//gm; # Trim trailing whitespace on each line in paragraph while (/^([^:]+):\s*(.*)/gm ) { # get mail header $headers{$1} = $2; } ####################################################################### 5:Pattern Matching/Positions/Boundaries: The C<\b> and C<\B> Assertions ####################################################################### /\bis\b/ # matches "what it is" and "that is it" /\Bis\B/ # matches "thistle" and "artist" /\bis\B/ # matches "istanbul" and "so--isn't that butter?" /\Bis\b/ # matches "confutatis" and "metropolis near you" ################################################# 5:Pattern Matching/Positions/Progressive Matching ################################################# $burglar = "Bilbo Baggins"; while ($burglar =~ /b/gi) { printf "Found a B at %d\n", pos($burglar)-1; } $burglar = "Bilbo Baggins"; while ($burglar =~ /b/gci) { # ADD /c printf "Found a B at %d\n", pos($burglar)-1; } while ($burglar =~ /i/gi) { printf "Found an I at %d\n", pos($burglar)-1; } #################################################################### 5:Pattern Matching/Positions/Where You Left Off: The C<\G> Assertion #################################################################### ($recipe = <<'DISH') =~ s/^\s+//gm; Preheat oven to 451 deg. fahrenheit. Mix 1 ml. dilithium with 3 oz. NaCl and stir in 4 anchovies. Glaze with 1 g. mercury. Heat for 4 hours and let cool for 3 seconds. Serves 10 aliens. DISH $recipe =~ /\d+ /g; $recipe =~ /\G(\w+)/; # $1 is now "deg" $recipe =~ /\d+ /g; $recipe =~ /\G(\w+)/; # $1 is now "ml" $recipe =~ /\d+ /g; $recipe =~ /\G(\w+)/; # $1 is now "oz" -------------- pos($recipe) = 0; # Just to be safe, reset \G to 0 while ( $recipe =~ /(\d+) /g ) { my $amount = $1; if ($recipe =~ / \G (\w{0,3}) \. \s+ (\w+) /x) { # abbrev. + word print "$amount $1 of $2\n"; } else { $recipe =~ / \G (\w+) /x; # just a word print "$amount $1\n"; } } ##################################################### 5:Pattern Matching/Capturing and Clustering/Capturing ##################################################### /(\d)(\d)/ # Match two digits, capturing them into $1 and $2 /(\d+)/ # Match one or more digits, capturing them all into $1 /(\d)+/ # Match a digit one or more times, capturing the last into $1 -------------- /\b(\w+) \1\b/i -------------- From: gnat@perl.com To: camelot@oreilly.com Date: Mon, 17 Jul 2000 09:00:00 -1000 Subject: Eye of the needle -------------- while (<>) { /^(.*?): (.*)$/; # Pre-colon text into $1, post-colon into $2 $fields{$1} = $2; } -------------- s/^(\S+) (\S+)/$2 $1/; # Swap first two words -------------- /^((\w+) (\w+))$/ -------------- ($first, $last) = /^(\w+) (\w+)$/; ($full, $first, $last) = /^((\w+) (\w+))$/; -------------- %fields = /^(.*?): (.*)$/gm; -------------- $_ = "Speak, friend, and enter."; m[ (<.*?>) (.*?) () ]x; # A tag, then chars, then an end tag print "prematch: $`\n"; # Speak, print "match: $&\n"; # friend print "postmatch: $'\n"; # , and enter. print "lastmatch: $+\n"; # -------------- #!/usr/bin/perl $alphabet = "abcdefghijklmnopqrstuvwxyz"; $alphabet =~ /(hi).*(stu)/; print "The entire match began at $-[0] and ended at $+[0]\n"; print "The first match began at $-[1] and ended at $+[1]\n"; print "The second match began at $-[2] and ended at $+[2]\n"; -------------- /\(e.g. .*?\)/ ###################################################### 5:Pattern Matching/Capturing and Clustering/Clustering ###################################################### @fields = split(/\b(?:a|b|c)\b/) -------------- @fields = split(/\b(a|b|c)\b/) ######################################################################## 5:Pattern Matching/Capturing and Clustering/Cloistered Pattern Modifiers ######################################################################## /Harry (?i:s) Truman/ -------------- /Harry (?x: [A-Z] \.? )? Truman/ -------------- /Harry (?ix: [A-Z] \.? )? Truman/ -------------- /Harry (?x-i: [A-Z] \.? )? Truman/i -------------- /(?i)foo/ # Equivalent to /foo/i /foo((?-i)bar)/i # "bar" must be lower case /foo((?x-i) bar)/ # Enables /x and disables /i for "bar" ############################## 5:Pattern Matching/Alternation ############################## /Gandalf|Saruman|Radagast/ -------------- /prob|n|r|l|ate/ # Match prob, n, r, l, or ate /pro(b|n|r|l)ate/ # Match probate, pronate, prorate, or prolate /pro(?:b|n|r|l)ate/ # Match probate, pronate, prorate, or prolate -------------- /(Sam|Samwise)/ -------------- "'Sam I am,' said Samwise" =~ /(Samwise|Sam)/; # $1 eq "Sam" -------------- "'Sam I am,' said Samwise" =~ /.*(Samwise|Sam)/; # $1 eq "Samwise" -------------- "'Sam I am,' said Samwise" =~ /(Samwise|Sam)$/; # $1 eq "Samwise" -------------- #!/usr/bin/perl while (<>) { print if /^__DATA__|^__END__/; } -------------- /^cat|dog|cow$/ -------------- /^(cat|dog|cow)$/ -------------- /^cat$|^dog$|^cow$/ -------------- /com(pound|)/; # Matches "compound" or "com" /com(pound(s|)|)/; # Matches "compounds", "compound", or "com" -------------- /com(pound)?/; # Matches "compound" or "com" /com(pound(s?))?/; # Matches "compounds", "compound", or "com" /com(pounds?)?/; # Same, but doesn't use $2 ############################################################## 5:Pattern Matching/Staying in Control/Letting Perl Do the Work ############################################################## /Gandalf|Saruman|Radagast/ -------------- /Gandalf/ || /Saruman/ || /Radagast/ -------------- while () { next if /^#/; next if /^\s*(#|$)/; chomp; munchabunch($_); } -------------- warn "has nondigits" if /\D/; warn "not a natural number" unless /^\d+$/; # rejects -3 warn "not an integer" unless /^-?\d+$/; # rejects +3 warn "not an integer" unless /^[+-]?\d+$/; warn "not a decimal number" unless /^-?\d+\.?\d*$/; # rejects .2 warn "not a decimal number" unless /^-?(?:\d+(?:\.\d*)?|\.\d+)$/; warn "not a C float" unless /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/; ############################################################ 5:Pattern Matching/Staying in Control/Variable Interpolation ############################################################ if ($num =~ /^[-+]?\d+\.?\d*$/) { ... } -------------- $sign = '[-+]?'; $digits = '\d+'; $decimal = '\.?'; $more_digits = '\d*'; $number = "$sign$digits$decimal$more_digits"; ... if ($num =~ /^$number$/o) { ... } -------------- chomp($answer = ); if ("SEND" =~ /^\Q$answer/i) { print "Action is send\n" } elsif ("STOP" =~ /^\Q$answer/i) { print "Action is stop\n" } elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" } elsif ("LIST" =~ /^\Q$answer/i) { print "Action is list\n" } elsif ("EDIT" =~ /^\Q$answer/i) { print "Action is edit\n" } #################################################################################### 5:Pattern Matching/Staying in Control/Variable Interpolation/When backslashes happen #################################################################################### ($col1, $col2) = /(.*?) \t+ (.*?)/x; -------------- $colsep = "\t+"; # (double quotes) ($col1, $col2) = /(.*?) $colsep (.*?)/x; -------------- $var = '\U'; /${var}frodo/; -------------- $hobbit = 'Frodo'; $var = '$hobbit'; # (single quotes) /$var/; # means m'$hobbit', not m'Frodo'. -------------- #!/usr/bin/perl $pattern = shift; while (<>) { print if /$pattern/o; } -------------- % pgrep '\t\d' *.c -------------- % pgrep '(?i)ring' LotR*.pod ########################################################################################## 5:Pattern Matching/Staying in Control/Variable Interpolation/The qr// quote regex operator ########################################################################################## print if /$pattern/o; -------------- foreach $item (@data) { foreach $patstr (@patterns) { if ($item =~ /$patstr/) { ... } } } -------------- $regex = qr/my.STRING/is; s/$regex/something else/; -------------- s/my.STRING/something else/is; -------------- @regexes = (); foreach $patstr (@patterns) { push @regexes, qr/$patstr/; } -------------- @regexes = map { qr/$patstr/ } @patterns; -------------- foreach $item (@data) { foreach $re (@regexes) { if ($item =~ /$re/) { ... } } } -------------- $regex = qr/$pattern/; $string =~ /foo${regex}bar/; # interpolate into larger patterns -------------- $re = qr/my.STRING/is; print $re; # prints (?si-xm:my.STRING) -------------- $re = qr/$pat/is; # might escape and eat you $re = eval { qr/$pat/is } || warn ... # caught it in an outer cage ######################################################## 5:Pattern Matching/Staying in Control/The Regex Compiler ######################################################## #!/usr/bin/perl use re "debug"; "Smeagol" =~ /^Sm(.*)g[aeiou]l$/; ########################################################################## 5:Pattern Matching/Staying in Control/The Little Engine that /Could(n't)?/ ########################################################################## /x*y*/ -------------- $a = 'nobody'; $b = 'bodysnatcher'; if ("$a $b" =~ /^(\w+)(\w+) \2(\w+)$/) { print "$2 overlaps in $1-$2-$3\n"; } ####################################################### 5:Pattern Matching/Fancy Patterns/Lookaround Assertions ####################################################### $_ = "Paris in THE THE THE THE spring."; # remove duplicate words (and triplicate (and quadruplicate...)) 1 while s/\b(\w+) \1\b/$1/gi; -------------- s/ \b(\w+) \s (?= \1\b ) //gxi; -------------- s/ \b(\w+) \s (?= \1\b (?! '\w))//xgi; -------------- s/ \b(\w+) \s (?= \1\b (?! '\w | \s particular))//gix; -------------- s/ \b(\w+) \s (?= \1\b (?! '\w | \s particular | \s nation))//igx; -------------- @thatthat = qw(particular nation); local $" = '|'; s/ \b(\w+) \s (?= \1\b (?! '\w | \s (?: @thatthat )))//xig; -------------- s/ \b(\w+) \s (?= \1\b (?! '\w | (?<= that) \s (?: @thatthat )))//ixg; -------------- s/(?a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*)[b]/; -------------- #!/usr/bin/perl -00p while ( /( (.+) ( (?<=\\) \n .* )+ ) /gx) { print "GOT $.: $1\n\n"; } -------------- (.+(?:(?<=\\)\n.*)+) -------------- ((?>.+)(?:(?<=\\)\n.*)+) ########################################################################## 5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Generated patterns ########################################################################## #!/usr/bin/perl $vowels = 'aeiouy'; $cons = 'cbdfghjklmnpqrstvwxzy'; %map = (C => $cons, V => $vowels); # init map for C and V for $class ($vowels, $cons) { # now for each type for (split //, $class) { # get each letter of that type $map{$_} .= $class; # and map the letter back to the type } } for $char (split //, shift) { # for each letter in template word $pat .= "[$map{$char}]"; # add appropriate character class } $re = qr/^${pat}$/i; # compile the pattern print "REGEX is $re\n"; # debugging output @ARGV = ('/usr/dict/words') # pick a default dictionary if -t && !@ARGV; while (<>) { # and now blaze through the input print if /$re/; # printing any line that matches } ################################################################################ 5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Substitution evaluations ################################################################################ s/(\d+)/$1 * 2/; # Replaces "42" with "42 * 2" s/(\d+)/$1 * 2/e; # Replaces "42" with "84" -------------- $_ = "Preheat oven to 233C.\n"; s/\b(\d+\.?\d*)C\b/int($1 * 1.8 + 32) . "F"/e; # convert to 451F -------------- % perl -pi -e 's/^(\d+)(?=:)/100 + $1/e' filename -------------- s/(\$\w+)/$1/eeg; # Interpolate most scalars' values -------------- $_ = "I have 4 + 19 dollars and 8/2 cents.\n"; s{ ( \d+ \s* # find an integer [+*/-] # and an arithmetical operator \s* \d+ # and another integer ) }{ $1 }eegx; # then expand $1 and run that code print; # "I have 23 dollars and 4 cents." ################################################################################## 5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Match-time code evaluation ################################################################################## "glyph" =~ /.+ (?{ print "hi" }) ./x; # Prints "hi" twice. -------------- $_ = 'lothlorien'; m/ (?{ $i = 0 }) # Set $i to 0 (. (?{ $i++ }) )* # Update $i, even after backtracking lori # Forces a backtrack /x; -------------- $_ = 'lothlorien'; m/ (?{ $i = 0 }) (. (?{ local $i = $i + 1; }) )* # Update $i, backtracking-safe. lori (?{ $result = $i }) # Copy to non-localized location. /x; -------------- "glyph" =~ /.+(?(?{ $foo{bar} gt "symbol" }).|signet)./; -------------- "glyph" =~ m{ .+ # some anythings (?(?{ # if $foo{bar} gt "symbol" # this is true }) . # match another anything | # else signet # match signet ) . # and one more anything }x; -------------- /(.*?) (?{length($1) < 3 && warn}) $suffix/; # Error without use re 'eval' -------------- /foo${pat}bar/ -------------- "abcdef" =~ / .+ (?{print "Matched so far: $&\n"}) bcdef $/x; ######################################################################################## 5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Match-time pattern interpolation ######################################################################################## /\w (??{ if ($threshold > 1) { "red" } else { "blue" } }) \d/x; -------------- /^ (.+) .? (??{quotemeta reverse $1}) $/xi; -------------- $text =~ /( \(+ ) (.*?) (??{ '\)' x length $1 })/x; -------------- $np = qr{ \( (?: (?> [^()]+ ) # Non-parens without backtracking | (??{ $np }) # Group with matching parens )* \) }x; -------------- $funpat = qr/\w+$np/; 'myfunfun(1,(2*(3+4)),5)' =~ /^$funpat$/; # Matches! ################################################################################# 5:Pattern Matching/Fancy Patterns/Programmatic Patterns/Conditional interpolation ################################################################################# #!/usr/bin/perl $x = 'Perl is free.'; $y = 'ManagerWare costs $99.95.'; foreach ($x, $y) { /^(\w+) (?:is|(costs)) (?(2)(\$\d+)|\w+)/; # Either (\$\d+) or \w+ if ($3) { print "$1 costs money.\n"; # ManagerWare costs money. } else { print "$1 doesn't cost money.\n"; # Perl doesn't cost money. } } -------------- /[ATGC]+(?(?<=AA)G|C)$/; ############################################################## 5:Pattern Matching/Fancy Patterns/Defining Your Own Assertions ############################################################## use Tagger; $_ = 'camel'; print "Tagged camel found" if /\tag\w+\tag/; -------------- package Tagger; use overload; sub import { overload::constant 'qr' => \&convert } sub convert { my $re = shift; $re =~ s/ \\tag /<.*?>/xg; $re =~ s/ \\w /[A-Za-z]/xg; return $re; } 1; -------------- $re = '\tag\w+\tag'; # This string begins with \t, a tab print if /$re/; # Matches a tab, followed by an "a"... -------------- $re = '\tag\w+\tag'; # This string begins with \t, a tab $re = Tagger::convert $re; # expand \tag and \w print if /$re/; # $re becomes <.*?>[A-Za-z]+<.*?> ####################### 6:Subroutines/Semantics ####################### sub razzle { print "Ok, you've been razzled.\n"; } -------------- razzle(); ################################################### 6:Subroutines/Semantics/Tricks with Parameter Lists ################################################### sub maysetenv { my ($key, $value) = @_; $ENV{$key} = $value unless $ENV{$key}; } -------------- sub max { my $max = shift(@_); for my $item (@_) { $max = $item if $max < $item; } return $max; } $bestday = max($mon,$tue,$wed,$thu,$fri); -------------- sub configuration { my %options = @_; print "Maximum verbosity.\n" if $options{VERBOSE} == 9; } configuration(PASSWORD => "xyzzy", VERBOSE => 9, SCORE => 0); -------------- upcase_in($v1, $v2); # this changes $v1 and $v2 sub upcase_in { for (@_) { tr/a-z/A-Z/ } } -------------- upcase_in("frederick"); -------------- ($v3, $v4) = upcase($v1, $v2); sub upcase { my @parms = @_; for (@parms) { tr/a-z/A-Z/ } # Check whether we were called in list context. return wantarray ? @parms : $parms[0]; } -------------- @newlist = upcase(@list1, @list2); @newlist = upcase( split /:/, $var ); -------------- (@a, @b) = upcase(@list1, @list2); # WRONG ######################################### 6:Subroutines/Semantics/Error Indications ######################################### if ($something_went_awry) { return if defined wantarray; # good, not void context. die "Pay attention to my error, you danglesocket!!!\n"; } ###################################### 6:Subroutines/Semantics/Scoping Issues ###################################### &foo(1,2,3); # pass three arguments foo(1,2,3); # the same foo(); # pass a null list &foo(); # the same &foo; # foo() gets current args, like foo(@_), but faster! foo; # like foo() if sub foo predeclared, else bareword "foo" -------------- # top of file my $x = 10; # declare and initialize variable sub bumpx { $x++ } # function can see outer lexical variable -------------- { my $counter = 0; sub next_counter { return ++$counter } sub prev_counter { return --$counter } } -------------- BEGIN { my @scale = ('A' .. 'G'); my $note = -1; sub next_pitch { return $scale[ ($note += 1) %= @scale ] }; } ################################ 6:Subroutines/Passing References ################################ $total = sum ( \@a ); sub sum { my ($aref) = @_; my ($total) = 0; foreach (@$aref) { $total += $_ } return $total; } -------------- @tailings = popmany ( \@a, \@b, \@c, \@d ); sub popmany { my @retlist = (); for my $aref (@_) { push @retlist, pop @$aref; } return @retlist; } -------------- @common = inter( \%foo, \%bar, \%joe ); sub inter { my %seen; for my $href (@_) { while (my $k = each %$href ) { $seen{$k}++; } } return grep { $seen{$_} == @_ } keys %seen; } -------------- (@a, @b) = func(@c, @d); -------------- (%a, %b) = func(%c, %d); -------------- ($aref, $bref) = func(\@c, \@d); print "@$aref has more than @$bref\n"; sub func { my ($cref, $dref) = @_; if (@$cref > @$dref) { return ($cref, $dref); } else { return ($dref, $cref); } } ######################## 6:Subroutines/Prototypes ######################## sub mypush (\@@); -------------- use Symbol 'qualify_to_ref'; sub foo (*) { my $fh = qualify_to_ref(shift, caller); ... } -------------- mytime +2; -------------- sub try (&$) { my ($try, $catch) = @_; eval { &$try }; if ($@) { local $_ = $@; &$catch; } } sub catch (&) { $_[0] } try { die "phooey"; } # not the end of the function call! catch { /phooey/ and print "unphooey\n"; }; -------------- sub mygrep (&@) { my $coderef = shift; my @result; foreach $_ (@_) { push(@result, $_) if &$coderef; } return @result; } #################################################### 6:Subroutines/Prototypes/Inlining Constant Functions #################################################### sub pi () { 3.14159 } # Not exact, but close. sub PI () { 4 * atan2(1, 1) } # As good as it gets -------------- sub FLAG_FOO () { 1 << 8 } sub FLAG_BAR () { 1 << 9 } sub FLAG_MASK () { FLAG_FOO | FLAG_BAR } sub OPT_GLARCH () { (0x1B58 & FLAG_MASK) == 0 } sub GLARCH_VAL () { if (OPT_GLARCH) { return 23 } else { return 42 } } sub N () { int(GLARCH_VAL) / 3 } BEGIN { # compiler runs this block at compile time my $prod = 1; # persistent, private variable for (1 .. N) { $prod *= $_ } sub NFACT () { $prod } } -------------- sub not_inlined () { return 23 || $$; } ############################################# 6:Subroutines/Prototypes/Care with Prototypes ############################################# sub func ($) { my $n = shift; print "you gave me $n\n"; } -------------- func @foo; # counts @foo elements func split /:/; # counts number of fields returned func "a", "b", "c"; # passes "a" only, discards "b" and "c" func("a", "b", "c"); # suddenly, a compiler error! -------------- sub func (\$) { my $nref = shift; print "you gave me $$nref\n"; } -------------- func @foo; # compiler error, saw @, want $ func split/:/; # compiler error, saw function, want $ func $s; # this one is ok -- got real $ symbol func $a[3]; # and this one func $h{stuff}[-1]; # or even this func 2+5; # scalar expr still a compiler error func ${ \(2+5) }; # ok, but is the cure worse than the disease? ########################################################################## 6:Subroutines/Subroutine Attributes/The C and C Attributes ########################################################################## # Only one thread is allowed into this function. sub afunc : locked { ... } # Only one thread is allowed into this function on a given object. sub afunc : locked method { ... } -------------- sub afunc : method { ... } -------------- sub fnord (&\%) : switch(10,foo(7,3)) : expensive; sub plugh () : Ugly('\(") :Bad; sub xyzzy : _5x5 { ... } -------------- sub fnord : switch(10,foo(); # ()-string not balanced sub snoid : Ugly('('); # ()-string not balanced sub xyzzy : 5x5; # "5x5" not a valid identifier sub plugh : Y2::north; # "Y2::north" not a simple identifier sub snurt : foo + bar; # "+" not a colon or space ########################################################### 6:Subroutines/Subroutine Attributes/The C attribute ########################################################### my $val; sub canmod : lvalue { $val; } sub nomod { $val; } canmod() = 5; # Assigns to $val. nomod() = 5; # ERROR -------------- canmod $x = 5; # assigns 5 to $x first! canmod 42 = 5; # can't change a constant; compile-time error canmod($x) = 5; # this is ok canmod(42) = 5; # and so is this -------------- canmod = 5; -------------- $obj->canmod = 5; -------------- data(2,3) = get_data(3,4); -------------- (data(2,3)) = get_data(3,4); -------------- (data(2),data(3)) = get_data(3,4); ######### 7:Formats ######### $value =~ tr/\n\t\f/ /; -------------- # a report on the /etc/passwd file format STDOUT_TOP = Passwd File Name Login Office Uid Gid Home ------------------------------------------------------------------ . format STDOUT = @<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<@>>>> @>>>> @<<<<<<<<<<<<<<<<< $name, $login, $office,$uid,$gid, $home . # a report from a bug report form format STDOUT_TOP = Bug Reports @<<<<<<<<<<<<<<<<<<<<<<< @||| @>>>>>>>>>>>>>>>>>>>>>>> $system, $%, $date ------------------------------------------------------------------ . format STDOUT = Subject: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $subject Index: @<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $index, $description Priority: @<<<<<<<<<< Date: @<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $priority, $date, $description From: @<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $from, $description Assigned to: @<<<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $programmer, $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<< $description ~ ^<<<<<<<<<<<<<<<<<<<<<<<... $description . ########################### 7:Formats//Format Variables ########################### select((select(OUTF), $~ = "My_Other_Format", $^ = "My_Top_Format" )[0]); -------------- $ofh = select(OUTF); $~ = "My_Other_Format"; $^ = "My_Top_Format"; select($ofh); -------------- use English; $ofh = select(OUTF); $FORMAT_NAME = "My_Other_Format"; $FORMAT_TOP_NAME = "My_Top_Format"; select($ofh); -------------- use FileHandle; OUTF->format_name("My_Other_Format"); OUTF->format_top_name("My_Top_Format"); -------------- format Ident = @<<<<<<<<<<<<<<< commify($n) . -------------- format Ident = I have an @ here. "@" . -------------- format Ident = @|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| "Some text line" . -------------- $format = "format STDOUT = \n" . '^' . '<' x $cols . "\n" . '$entry' . "\n" . "\t^" . "<" x ($cols-8) . "~~\n" . '$entry' . "\n" . ".\n"; print $format if $Debugging; eval $format; die $@ if $@; -------------- format STDOUT = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $entry ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<~~ $entry . -------------- format = ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~ $_ . $/ = ""; while (<>) { s/\s*\n\s*/ /g; write; } ######################################### 7:Formats//Accessing Formatting Internals ######################################### $str = formline <<'END', 1,2,3; @<<< @||| @>>> END print "Wow, I just stored `$^A' in the accumulator!\n"; -------------- use Carp; sub swrite { croak "usage: swrite PICTURE ARGS" unless @_; my $format = shift; $^A = ""; formline($format, @_); return $^A; } $string = swrite(<<'END', 1, 2, 3); Check me out @<<< @||| @>>> END print $string; -------------- use FileHandle; STDOUT->formline("^" . ("<" x 72) . "~~\n", $long_text); ############ 8:References ############ @john = (47, "brown", 186); @mary = (23, "hazel", 128); @bill = (35, "blue", 157); -------------- @vitals = ('john', 'mary', 'bill'); ####################################################### 8:References/Creating References/The Backslash Operator ####################################################### $scalarref = \$foo; $constref = \186_282.42; $arrayref = \@ARGV; $hashref = \%ENV; $coderef = \&handler; $globref = \*STDOUT; ############################################################################ 8:References/Creating References/Anonymous Data/The anonymous array composer ############################################################################ $arrayref = [1, 2, ['a', 'b', 'c', 'd']]; -------------- $table = [ [ "john", 47, "brown", 186], [ "mary", 23, "hazel", 128], [ "bill", 35, "blue", 157] ]; ########################################################################### 8:References/Creating References/Anonymous Data/The anonymous hash composer ########################################################################### $hashref = { 'Adam' => 'Eve', 'Clyde' => $bonnie, 'Antony' => 'Cleo' . 'patra', }; -------------- $table = { "john" => [ 47, "brown", 186 ], "mary" => [ 23, "hazel", 128 ], "bill" => [ 35, "blue", 157 ], }; -------------- $table = { "john" => { age => 47, eyes => "brown", weight => 186, }, "mary" => { age => 23, eyes => "hazel", weight => 128, }, "bill" => { age => 35, eyes => "blue", weight => 157, }, }; -------------- sub hashem { { @_ } } # Silently WRONG -- returns @_. sub hashem { +{ @_ } } # Ok. sub hashem { return { @_ } } # Ok. ################################################################################# 8:References/Creating References/Anonymous Data/The anonymous subroutine composer ################################################################################# $coderef = sub { print "Boink!\n" }; # Now &$coderef prints "Boink!" #################################################### 8:References/Creating References/Object Constructors #################################################### $objref = Doggie::->new(Tail => 'short', Ears => 'long'); #1 $objref = new Doggie:: Tail => 'short', Ears => 'long'; #2 $objref = Doggie->new(Tail => 'short', Ears => 'long'); #3 $objref = new Doggie Tail => 'short', Ears => 'long'; #4 ################################################## 8:References/Creating References/Handle References ################################################## splutter(\*STDOUT); sub splutter { my $fh = shift; print $fh "her um well a hmmm\n"; } $rec = get_rec(\*STDIN); sub get_rec { my $fh = shift; return scalar <$fh>; } -------------- for $file (@names) { local *FH; open(*FH, $file) || next; $handle{$file} = *FH; } -------------- for $file (@names) { my $fh; open($fh, $file) || next; $handle{$file} = $fh; } ######################################################## 8:References/Creating References/Symbol Table References ######################################################## $scalarref = *foo{SCALAR}; # Same as \$foo $arrayref = *ARGV{ARRAY}; # Same as \@ARGV $hashref = *ENV{HASH}; # Same as \%ENV $coderef = *handler{CODE}; # Same as \&handler $globref = *foo{GLOB}; # Same as \*foo $ioref = *STDIN{IO}; # Er... -------------- splutter(*STDOUT); splutter(*STDOUT{IO}); sub splutter { my $fh = shift; print $fh "her um well a hmmm\n"; } ###################################################################### 8:References/Using Hard References/Using a Variable as a Variable Name ###################################################################### $foo = "three humps"; $scalarref = \$foo; # $scalarref is now a reference to $foo $camel_model = $$scalarref; # $camel_model is now "three humps" -------------- $bar = $$scalarref; push(@$arrayref, $filename); $$arrayref[0] = "January"; # Set the first element of @$arrayref @$arrayref[4..6] = qw/May June July/; # Set several elements of @$arrayref %$hashref = (KEY => "RING", BIRD => "SING"); # Initialize whole hash $$hashref{KEY} = "VALUE"; # Set one key/value pair @$hashref{"KEY1","KEY2"} = ("VAL1","VAL2"); # Set several pairs &$coderef(1,2,3); print $handleref "output\n"; -------------- $refrefref = \\\"howdy"; print $$$$refrefref; ###################################################################### 8:References/Using Hard References/Using a BLOCK as a Variable Name ###################################################################### $bar = ${$scalarref}; push(@{$arrayref}, $filename); ${$arrayref}[0] = "January"; @{$arrayref}[4..6] = qw/May June July/; ${$hashref}{"KEY"} = "VALUE"; @{$hashref}{"KEY1","KEY2"} = ("VAL1","VAL2"); &{$coderef}(1,2,3); -------------- $refrefref = \\\"howdy"; print ${${${$refrefref}}}; -------------- &{ $dispatch{$index} }(1, 2, 3); ########################################################### 8:References/Using Hard References/Using the Arrow Operator ########################################################### $ $arrayref [2] = "Dorian"; #1 ${ $arrayref }[2] = "Dorian"; #2 $arrayref->[2] = "Dorian"; #3 $ $hashref {KEY} = "F#major"; #1 ${ $hashref }{KEY} = "F#major"; #2 $hashref->{KEY} = "F#major"; #3 & $coderef (Presto => 192); #1 &{ $coderef }(Presto => 192); #2 $coderef->(Presto => 192); #3 -------------- print $array[3]->{"English"}->[0]; -------------- $array[3]->{"English"}->[0] = "January"; -------------- $dispatch{$index}(1, 2, 3); $array[3]{"English"}[0] = "January"; -------------- $answer[$x][$y][$z] += 42; -------------- $listref->[2][2] = "hello"; # Pretty clear $$listref[2][2] = "hello"; # A bit confusing -------------- $listref[2]->[$greeting] = "hello"; ############################################### 8:References/Using Hard References/Pseudohashes ############################################### $john = [ {age => 1, eyes => 2, weight => 3}, 47, "brown", 186 ]; -------------- $john->{weight} # Treats $john as a hashref $john->[3] # Treats $john as an arrayref -------------- $john->[0]{height} = 4; # height is to be element 4 $john->{height} = "tall"; # Or $john->[4] = "tall" -------------- delete $john->[0]{height}; # Deletes from the underlying hash only $john->{height}; # This now raises an exception $john->[4]; # Still prints "tall" -------------- use fields; $ph = fields::phash(age => 47, eyes => "brown", weight => 186); print $ph->{age}; -------------- use fields; $ph= fields::phash([qw(age eyes brown)], [47]); $ph->{eyes} = undef; print exists $ph->{age}; # True, 'age' was set in declaration. print exists $ph->{weight}; # False, 'weight' has not been used. print exists $ph->{eyes}; # True, your 'eyes' have been touched. -------------- print exists $ph->[0]{age}; # True, 'page' is a valid field print exists $ph->[0]{name}; # False, 'name' can't be used -------------- print delete $ph->{age}; # Removes and returns $ph->[1], 47 print exists $ph->{age}; # Now false print exists $ph->[0]{age}; # True, 'age' key still usable print delete $ph->[0]{age}; # Now 'age' key is gone print $ph->{age}; # Run-time exception ############################################################################### 8:References/Using Hard References/Other Tricks You Can Do with Hard References ############################################################################### @reflist = (\$s, \@a, \%h, \&f); # List of four references @reflist = \($s, @a %h, &f); # Same thing -------------- @reflist = \(@x); # Interpolate array, then get refs @reflist = map { \$_ } @x; # Same thing -------------- @reflist = \(@x, (@y)); # But only single aggregates expand @reflist = (\@x, map { \$_ } @y); # Same thing -------------- @envrefs = \@ENV{'HOME', 'TERM'}; # Backslashing a slice @envrefs = \( $ENV{HOME}, $ENV{TERM} ); # Backslashing a list @envrefs = ( \$ENV{HOME}, \$ENV{TERM} ); # A list of two references -------------- @reflist = \fx(); @reflist = map { \$_ } fx(); # Same thing @reflist = \( fx(), fy(), fz() ); @reflist = ( \fx(), \fy(), \fz() ); # Same thing @reflist = map { \$_ } fx(), fy(), fz(); # Same thing -------------- @reflist = \localtime(); # Ref to each of nine time elements $lastref = \localtime(); # Ref to whether it's daylight savings time -------------- $dateref = \scalar localtime(); # \"Sat Jul 16 11:42:18 2000" -------------- sub sum { my $arrayref = shift; warn "Not an array reference" if ref($arrayref) ne "ARRAY"; return eval join("+", @$arrayref); } -------------- print "My sub returned @{[ mysub(1,2,3) ]} that time.\n"; -------------- print "We need @{ [$n + 5] } widgets!\n"; -------------- print "mysub returns @{ [scalar mysub(1,2,3)] } now.\n"; ########################################### 8:References/Using Hard References/Closures ########################################### { my $critter = "camel"; $critterref = \$critter; } -------------- { my $critter = "camel"; $critterref = sub { return $critter }; } -------------- sub make_saying { my $salute = shift; my $newfunc = sub { my $target = shift; print "$salute, $target!\n"; }; return $newfunc; # Return a closure } $f = make_saying("Howdy"); # Create a closure $g = make_saying("Greetings"); # Create another closure # Time passes... $f->("world"); $g->("earthlings"); -------------- sub get_method_ref { my ($self, $methodname) = @_; my $methref = sub { # the @_ below is not the same as the one above! return $self->$methodname(@_); }; return $methref; } my $dog = new Doggie:: Name => "Lucky", Legs => 3, Tail => "clipped"; our $wagger = get_method_ref($dog, 'wag'); $wagger->("tail"); # Calls $dog->wag('tail'). ########################################################################## 8:References/Using Hard References/Closures/Closures as function templates ########################################################################## print "Be ", red("careful"), "with that ", green("light"), "!!!"; -------------- @colors = qw(red blue green yellow orange purple violet); for my $name (@colors) { no strict 'refs'; # Allow symbolic references *$name = *{uc $name} = sub { "@_" }; } -------------- *$name = sub ($) { "$_[0]" }; ############################################################## 8:References/Using Hard References/Closures/Nested subroutines ############################################################## sub outer { my $x = $_[0] + 35; local *inner = sub { return $x * 19 }; return $x + inner(); } -------------- sub outer { my $x = $_[0] + 35; my $inner = sub { return $x * 19 }; return $x + $inner->(); } ################################ 8:References/Symbolic References ################################ $name = "bam"; $$name = 1; # Sets $bam $name->[0] = 4; # Sets the first element of @bam $name->{X} = "Y"; # Sets the X element of %bam to Y @$name = (); # Clears @bam keys %$name; # Yields the keys of %bam &$name; # Calls &bam -------------- use strict 'refs'; -------------- no strict 'refs'; -------------- ${identifier}; # Same as $identifier. ${"identifier"}; # Also $identifier, but a symbolic reference. -------------- our $value = "global"; { my $value = "private"; print "Inside, mine is ${value}, "; print "but ours is ${'value'}.\n"; } print "Outside, ${value} is again ${'value'}.\n"; ########################################## 8:References/Braces, Brackets, and Quoting ########################################## $push = "pop on "; print "${push}over"; -------------- print ${push} . 'over'; -------------- print ${ push } . 'over'; -------------- $hash{ "aaa" }{ "bbb" }{ "ccc" } -------------- $hash{ aaa }{ bbb }{ ccc } -------------- $hash{aaa}{bbb}{ccc} -------------- $hash{ shift } -------------- $hash{ shift() } $hash{ +shift } $hash{ shift @_ } ############################################################################# 8:References/Braces, Brackets, and Quoting/References Don't Work as Hash Keys ############################################################################# $x{ \$a } = $a; ($key, $value) = each %x; print $$key; # WRONG -------------- $r = \@a; $x{ $r } = $r; -------------- use Tie::RefHash; tie my %h, 'Tie::RefHash'; %h = ( ["this", "here"] => "at home", ["that", "there"] => "elsewhere", ); while ( my($keyref, $value) = each %h ) { print "@$keyref is $value\n"; } ####################################################################################################### 8:References/Braces, Brackets, and Quoting/Garbage Collection, Circular References, and Weak References ####################################################################################################### { # make $a and $b point to each other my ($a, $b); $a = \$b; $b = \$a; } -------------- { # make $a point to itself my $a; $a = \$a; } ################################################################################################################# 9:Data Structures/A Brief Tutorial: Manipulating Arrays of Arrays/Creating and Accessing a Two-Dimensional Array ################################################################################################################# # Assign a list of array references to an array. @AoA = ( [ "fred", "barney" ], [ "george", "jane", "elroy" ], [ "homer", "marge", "bart" ], ); print $AoA[2][1]; # prints "marge" -------------- # Create an reference to an array of array references. $ref_to_AoA = [ [ "fred", "barney", "pebbles", "bamm bamm", "dino", ], [ "homer", "bart", "marge", "maggie", ], [ "george", "jane", "elroy", "judy", ], ]; print $ref_to_AoA->[2][3]; # prints "judy" -------------- $AoA[2][3] $ref_to_AoA->[2][3] -------------- $AoA[2]->[3] $ref_to_AoA->[2]->[3] -------------- $AoA[0][-2] ################################################################################### 9:Data Structures/A Brief Tutorial: Manipulating Arrays of Arrays/Growing Your Own ################################################################################### while (<>) { @tmp = split; # Split elements into an array. push @AoA, [ @tmp ]; # Add an anonymous array reference to @AoA. } -------------- while (<>) { push @AoA, [ split ]; } -------------- while (<>) { push @$ref_to_AoA, [ split ]; } -------------- for $x (0 .. 9) { # For each row... for $y (0 .. 9) { # For each column... $AoA[$x][$y] = func($x, $y); # ...set that cell } } for $x ( 0..9 ) { # For each row... $ref_to_AoA->[$x][3] = func2($x); # ...set the fourth column } -------------- # Append new columns to an existing row. push @{ $AoA[0] }, "wilma", "betty"; -------------- push $AoA[0], "wilma", "betty"; # WRONG! ###################################################################################### 9:Data Structures/A Brief Tutorial: Manipulating Arrays of Arrays/Access and Printing ###################################################################################### print $AoA[3][2]; -------------- print @AoA; # WRONG -------------- for $row ( @AoA ) { print "@$row\n"; } -------------- for $i ( 0 .. $#AoA ) { print "row $i is: @{$AoA[$i]}\n"; } -------------- for $i ( 0 .. $#AoA ) { for $j ( 0 .. $#{$AoA[$i]} ) { print "element $i $j is $AoA[$i][$j]\n"; } } -------------- for $i ( 0 .. $#AoA ) { $row = $AoA[$i]; for $j ( 0 .. $#{$row} ) { print "element $i $j is $row->[$j]\n"; } } ######################################################################### 9:Data Structures/A Brief Tutorial: Manipulating Arrays of Arrays/Slices ######################################################################### @part = (); for ($y = 7; $y < 13; $y++) { push @part, $AoA[4][$y]; } -------------- @part = @{ $AoA[4] } [ 7..12 ]; -------------- @newAoA = (); for ($startx = $x = 4; $x <= 8; $x++) { for ($starty = $y = 7; $y <= 12; $y++) { $newAoA[$x - $startx][$y - $starty] = $AoA[$x][$y]; } } -------------- for ($x = 4; $x <= 8; $x++) { push @newAoA, [ @{ $AoA[$x] } [ 7..12 ] ]; } ################################################################################## 9:Data Structures/A Brief Tutorial: Manipulating Arrays of Arrays/Common Mistakes ################################################################################## @AoA = ( [2, 3], [4, 5, 7], [0] ); print "@AoA"; -------------- print $AoA[1][2]; -------------- for $i (1..10) { @array = somefunc($i); $AoA[$i] = @array; # WRONG! } -------------- for $i (1..10) { @array = somefunc($i); $AoA[$i] = \@array; # WRONG AGAIN! } -------------- for $i (1..10) { @array = somefunc($i); $AoA[$i] = [ @array ]; # RIGHT! } -------------- for $i (1..10) { @array = somefunc($i); @{$AoA[$i]} = @array; } -------------- $AoA[3] = \@original_array; -------------- @{$AoA[3]} = @array; -------------- for $i (1..10) { my @array = somefunc($i); $AoA[$i] = \@array; } -------------- for $i (1..10) { $AoA[$i] = [ somefunc($i) ]; } -------------- $AoA[$i] = [ @array ]; # Safest, sometimes fastest $AoA[$i] = \@array; # Fast but risky, depends on my-ness of array @{ $AoA[$i] } = @array; # Too tricky for most uses ################################################################## 9:Data Structures/Hashes of Arrays/Composition of a Hash of Arrays ################################################################## # We customarily omit quotes when the keys are identifiers. %HoA = ( flintstones => [ "fred", "barney" ], jetsons => [ "george", "jane", "elroy" ], simpsons => [ "homer", "marge", "bart" ], ); -------------- $HoA{teletubbies} = [ "tinky winky", "dipsy", "laa-laa", "po" ]; ################################################################# 9:Data Structures/Hashes of Arrays/Generation of a Hash of Arrays ################################################################# while ( <> ) { next unless s/^(.*?):\s*//; $HoA{$1} = [ split ]; } while ( $line = <> ) { ($who, $rest) = split /:\s*/, $line, 2; @fields = split ' ', $rest; $HoA{$who} = [ @fields ]; } -------------- for $group ( "simpsons", "jetsons", "flintstones" ) { $HoA{$group} = [ get_family($group) ]; } for $group ( "simpsons", "jetsons", "flintstones" ) { @members = get_family($group); $HoA{$group} = [ @members ]; } -------------- push @{ $HoA{flintstones} }, "wilma", "pebbles"; ########################################################################## 9:Data Structures/Hashes of Arrays/Access and Printing of a Hash of Arrays ########################################################################## $HoA{flintstones}[0] = "Fred"; -------------- $HoA{simpsons}[1] =~ s/(\w)/\u$1/; -------------- for $family ( keys %HoA ) { print "$family: @{ $HoA{$family} }\n"; } -------------- for $family ( keys %HoA ) { print "$family: "; for $i ( 0 .. $#{ $HoA{$family} } ) { print " $i = $HoA{$family}[$i]"; } print "\n"; } -------------- for $family ( sort { @{$HoA{$b}} <=> @{$HoA{$a}} } keys %HoA ) { print "$family: @{ $HoA{$family} }\n" } -------------- # Print the whole thing sorted by number of members and name. for $family ( sort { @{$HoA{$b}} <=> @{$HoA{$a}} } keys %HoA ) { print "$family: ", join(", ", sort @{ $HoA{$family} }), "\n"; } #################################################################### 9:Data Structures/Arrays of Hashes/Composition of an Array of Hashes #################################################################### @AoH = ( { husband => "barney", wife => "betty", son => "bamm bamm", }, { husband => "george", wife => "jane", son => "elroy", }, { husband => "homer", wife => "marge", son => "bart", }, ); -------------- push @AoH, { husband => "fred", wife => "wilma", son => "junior" }; ################################################################### 9:Data Structures/Arrays of Hashes/Generation of an Array of Hashes ################################################################### while ( <> ) { $rec = {}; for $field ( split ) { ($key, $value) = split /=/, $field; $rec->{$key} = $value; } push @AoH, $rec; } while ( <> ) { push @AoH, { split /[\s=]+/ }; } -------------- while ( @fields = get_next_pair() ) { push @AoH, { @fields }; } while (<>) { push @AoH, { get_next_pair($_) }; } -------------- $AoH[0]{pet} = "dino"; $AoH[2]{pet} = "santa's little helper"; ############################################################################ 9:Data Structures/Arrays of Hashes/Access and Printing of an Array of Hashes ############################################################################ $AoH[0]{husband} = "fred"; -------------- $AoH[1]{husband} =~ s/(\w)/\u$1/; -------------- for $href ( @AoH ) { print "{ "; for $role ( keys %$href ) { print "$role=$href->{$role} "; } print "}\n"; } -------------- for $i ( 0 .. $#AoH ) { print "$i is { "; for $role ( keys %{ $AoH[$i] } ) { print "$role=$AoH[$i]{$role} "; } print "}\n"; } ################################################################## 9:Data Structures/Hashes of Hashes/Composition of a Hash of Hashes ################################################################## %HoH = ( flintstones => { husband => "fred", pal => "barney", }, jetsons => { husband => "george", wife => "jane", "his boy" => "elroy", # Key quotes needed. }, simpsons => { husband => "homer", wife => "marge", kid => "bart", }, ); -------------- $HoH{ mash } = { captain => "pierce", major => "burns", corporal => "radar", }; ################################################################# 9:Data Structures/Hashes of Hashes/Generation of a Hash of Hashes ################################################################# while ( <> ) { next unless s/^(.*?):\s*//; $who = $1; for $field ( split ) { ($key, $value) = split /=/, $field; $HoH{$who}{$key} = $value; } } while ( <> ) { next unless s/^(.*?):\s*//; $who = $1; $rec = {}; $HoH{$who} = $rec; for $field ( split ) { ($key, $value) = split /=/, $field; $rec->{$key} = $value; } } -------------- for $group ( "simpsons", "jetsons", "flintstones" ) { $HoH{$group} = { get_family($group) }; } for $group ( "simpsons", "jetsons", "flintstones" ) { @members = get_family($group); $HoH{$group} = { @members }; } sub hash_families { my @ret; for $group ( @_ ) { push @ret, $group, { get_family($group) }; } @ret; } %HoH = hash_families( "simpsons", "jetsons", "flintstones" ); -------------- %new_folks = ( wife => "wilma", pet => "dino"; ); for $what (keys %new_folks) { $HoH{flintstones}{$what} = $new_folks{$what}; } ########################################################################## 9:Data Structures/Hashes of Hashes/Access and Printing of a Hash of Hashes ########################################################################## $HoH{flintstones}{wife} = "wilma"; -------------- $HoH{jetsons}{'his boy'} =~ s/(\w)/\u$1/; -------------- for $family ( keys %HoH ) { print "$family: "; for $role ( keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; } -------------- while ( ($family, $roles) = each %HoH ) { print "$family: "; while ( ($role, $person) = each %$roles ) { print "$role=$person "; } print "\n"; } -------------- for $family ( sort keys %HoH ) { print "$family: "; for $role ( sort keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; } -------------- for $family ( sort { keys %{$HoH{$a}} <=> keys %{$HoH{$b}} } keys %HoH ) { print "$family: "; for $role ( sort keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; } -------------- $i = 0; for ( qw(husband wife son daughter pal pet) ) { $rank{$_} = ++$i } for $family ( sort { keys %{$HoH{$a}} <=> keys %{$HoH{$b}} } keys %HoH ) { print "$family: "; for $role ( sort { $rank{$a} <=> $rank{$b} } keys %{ $HoH{$family} } ) { print "$role=$HoH{$family}{$role} "; } print "\n"; } ##################################### 9:Data Structures/Hashes of Functions ##################################### if ($cmd =~ /^exit$/i) { exit } elsif ($cmd =~ /^help$/i) { show_help() } elsif ($cmd =~ /^watch$/i) { $watch = 1 } elsif ($cmd =~ /^mail$/i) { mail_msg($msg) } elsif ($cmd =~ /^edit$/i) { $edited++; editmsg($msg); } elsif ($cmd =~ /^delete$/i) { confirm_kill() } else { warn "Unknown command: `$cmd'; Try `help' next time\n"; } -------------- %HoF = ( # Compose a hash of functions exit => sub { exit }, help => \&show_help, watch => sub { $watch = 1 }, mail => sub { mail_msg($msg) }, edit => sub { $edited++; editmsg($msg); }, delete => \&confirm_kill, ); if ($HoF{lc $cmd}) { $HoF{lc $cmd}->() } # Call function else { warn "Unknown command: `$cmd'; Try `help' next time\n" } #################################################################################################### 9:Data Structures/More Elaborate Records/Composition, Access, and Printing of More Elaborate Records #################################################################################################### $rec = { TEXT => $string, SEQUENCE => [ @old_values ], LOOKUP => { %some_table }, THATCODE => \&some_function, THISCODE => sub { $_[0] ** $_[1] }, HANDLE => \*STDOUT, }; -------------- print $rec->{TEXT}; -------------- print $rec->{SEQUENCE}[0]; $last = pop @{ $rec->{SEQUENCE} }; print $rec->{LOOKUP}{"key"}; ($first_k, $first_v) = each %{ $rec->{LOOKUP} }; -------------- $that_answer = $rec->{THATCODE}->($arg1, $arg2); $this_answer = $rec->{THISCODE}->($arg1, $arg2); -------------- print { $rec->{HANDLE} } "a string\n"; -------------- use FileHandle; $rec->{HANDLE}->autoflush(1); $rec->{HANDLE}->print("a string\n"); ######################################################################################################### 9:Data Structures/More Elaborate Records/Composition, Access, and Printing of Even More Elaborate Records ######################################################################################################### %TV = ( flintstones => { series => "flintstones", nights => [ "monday", "thursday", "friday" ], members => [ { name => "fred", role => "husband", age => 36, }, { name => "wilma", role => "wife", age => 31, }, { name => "pebbles", role => "kid", age => 4, }, ], }, jetsons => { series => "jetsons", nights => [ "wednesday", "saturday" ], members => [ { name => "george", role => "husband", age => 41, }, { name => "jane", role => "wife", age => 39, }, { name => "elroy", role => "kid", age => 9, }, ], }, simpsons => { series => "simpsons", nights => [ "monday" ], members => [ { name => "homer", role => "husband", age => 34, }, { name => "marge", role => "wife", age => 37, }, { name => "bart", role => "kid", age => 11, }, ], }, ); ################################################################################ 9:Data Structures/More Elaborate Records/Generation of a Hash of Complex Records ################################################################################ $rec = {}; $rec->{series} = "flintstones"; $rec->{nights} = [ find_days() ]; -------------- @members = (); while (<>) { %fields = split /[\s=]+/; push @members, { %fields }; } $rec->{members} = [ @members ]; -------------- $TV{ $rec->{series} } = $rec; -------------- for $family (keys %TV) { my $rec = $TV{$family}; # temporary pointer @kids = (); for $person ( @{$rec->{members}} ) { if ($person->{role} =~ /kid|son|daughter/) { push @kids, $person; } } # $rec and $TV{$family} point to same data! $rec->{kids} = [ @kids ]; } -------------- $TV{simpsons}{kids}[0]{age}++; -------------- print $TV{simpsons}{members}[2]{age}; -------------- for $family ( keys %TV ) { print "the $family"; print " is on ", join (" and ", @{ $TV{$family}{nights} }), "\n"; print "its members are:\n"; for $who ( @{ $TV{$family}{members} } ) { print " $who->{name} ($who->{role}), age $who->{age}\n"; } print "children: "; print join (", ", map { $_->{name} } @{ $TV{$family}{kids} } ); print "\n\n"; } ######################################## 9:Data Structures/Saving Data Structures ######################################## use Data::Dumper; $Data::Dumper::Purity = 1; # since %TV is self-referential open (FILE, "> tvinfo.perldata") or die "can't open tvinfo: $!"; print FILE Data::Dumper->Dump([\%TV], ['*TV']); close FILE or die "can't close tvinfo: $!"; -------------- open (FILE, "< tvinfo.perldata") or die "can't open tvinfo: $!"; undef $/; # read in file all at once eval ; # recreate %TV die "can't recreate tv data from tvinfo.perldata: $@" if $@; close FILE or die "can't close tvinfo: $!"; print $TV{simpsons}{members}[2]{age}; -------------- do "tvinfo.perldata" or die "can't recreate tvinfo: $! $@"; print $TV{simpsons}{members}[2]{age}; ########### 10:Packages ########### $SIG{QUIT} = "Pkg::quit_catcher"; # fully qualified handler name $SIG{QUIT} = "quit_catcher"; # implies "main::quit_catcher" $SIG{QUIT} = *quit_catcher; # forces current package's sub $SIG{QUIT} = \&quit_catcher; # forces current package's sub $SIG{QUIT} = sub { print "Caught SIGQUIT\n" }; # anonymous sub ######################### 10:Packages/Symbol Tables ######################### *sym = *main::variable; *sym = $main::{"variable"}; -------------- foreach $symname (sort keys %main::) { local *sym = $main::{$symname}; print "\$$symname is defined\n" if defined $sym; print "\@$symname is nonnull\n" if @sym; print "\%$symname is nonnull\n" if %sym; } -------------- $!@#$% = 0; # WRONG, syntax error. ${'!@#$%'} = 1; # Ok, though unqualified. ${'main::!@#$%'} = 2; # Can qualify within the string. print ${ $main::{'!@#$%'} } # Ok, prints 2! -------------- *dick = *richard; -------------- *dick = \$richard; -------------- *SomePack::dick = \&OtherPack::richard; -------------- *units = populate() ; # Assign \%newhash to the typeglob print $units{kg}; # Prints 70; no dereferencing needed! sub populate { my %newhash = (km => 10, kg => 70); return \%newhash; } -------------- %units = (miles => 6, stones => 11); fillerup( \%units ); # Pass in a reference print $units{quarts}; # Prints 4 sub fillerup { local *hashsym = shift; # Assign \%units to the typeglob $hashsym{quarts} = 4; # Affects %units; no dereferencing needed! } -------------- *PI = \3.14159265358979; -------------- use constant PI => 3.14159; -------------- *PI = sub () { 3.14159 }; -------------- *sym = *oldvar; *sym = \*oldvar; # auto-dereference *sym = *{"oldvar"}; # explicit symbol table lookup *sym = "oldvar"; # implicit symbol table lookup -------------- *sym = \$frodo; *sym = \@sam; *sym = \%merry; *sym = \&pippin; -------------- *pkg::sym{SCALAR} # same as \$pkg::sym *pkg::sym{ARRAY} # same as \@pkg::sym *pkg::sym{HASH} # same as \%pkg::sym *pkg::sym{CODE} # same as \&pkg::sym *pkg::sym{GLOB} # same as \*pkg::sym *pkg::sym{IO} # internal file/dir handle, no direct equivalent *pkg::sym{NAME} # "sym" (not a reference) *pkg::sym{PACKAGE} # "pkg" (not a reference) -------------- sub identify_typeglob { my $glob = shift; print 'You gave me ', *{$glob}{PACKAGE}, '::', *{$glob}{NAME}, "\n"; } identify_typeglob(*foo); identify_typeglob(*bar::glarch); ####################### 10:Packages/Autoloading ####################### sub AUTOLOAD { our $AUTOLOAD; warn "Attempt to call $AUTOLOAD failed.\n"; } blarg(10); # our $AUTOLOAD will be set to main::blarg print "Still alive!\n"; -------------- sub AUTOLOAD { our $AUTOLOAD; return "I see $AUTOLOAD(@_)\n"; } print blarg(20); # prints: I see main::blarg(20) -------------- sub AUTOLOAD { my $name = our $AUTOLOAD; *$AUTOLOAD = sub { print "I see $name(@_)\n" }; goto &$AUTOLOAD; # Restart the new routine. } blarg(30); # prints: I see main::blarg(30) glarb(40); # prints: I see main::glarb(40) blarg(50); # prints: I see main::blarg(50) -------------- sub AUTOLOAD { my $program = our $AUTOLOAD; $program =~ s/.*:://; # trim package name system($program, @_); } -------------- date(); who('am', 'i'); ls('-l'); echo("Abadugabudabuda..."); -------------- sub date (;$$); # Allow zero to two arguments. sub who (;$$$$); # Allow zero to four args. sub ls; # Allow any number of args. sub echo ($@); # Allow at least one arg. date; who "am", "i"; ls "-l"; echo "That's all, folks!"; ######################## 11:Modules/Using Modules ######################## use Fred; # If Fred.pm has @EXPORT = qw(flintstone) flintstone(); # ...this calls Fred::flintstone(). ########################### 11:Modules/Creating Modules ########################### package Bestiary; require Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(camel); # Symbols to be exported by default our @EXPORT_OK = qw($weight); # Symbols to be exported on request our $VERSION = 1.00; # Version number ### Include your variables and functions here sub camel { print "One-hump dromedary" } $weight = 1024; 1; ########################################################### 11:Modules/Creating Modules/Module Privacy and the Exporter ########################################################### require Exporter; our @ISA = ("Exporter"); -------------- our @EXPORT = qw($camel %wolf ram); # Export by default our @EXPORT_OK = qw(leopard @llama $emu); # Export by request our %EXPORT_TAGS = ( # Export as group camelids => [qw($camel @llama)], critters => [qw(ram $camel %wolf)], ); -------------- use Bestiary; # Import @EXPORT symbols use Bestiary (); # Import nothing use Bestiary qw(ram @llama); # Import the ram function and @llama array use Bestiary qw(:camelids); # Import $camel and @llama use Bestiary qw(:DEFAULT); # Import @EXPORT symbols use Bestiary qw(/am/); # Import $camel, @llama, and ram use Bestiary qw(/^\$/); # Import all scalars use Bestiary qw(:critters !ram); # Import the critters, but exclude ram use Bestiary qw(:critters !:camelids); # Import critters, but no camelids -------------- BEGIN { require Bestiary; import Bestiary LIST; } ########################################################################################################## 11:Modules/Creating Modules/Module Privacy and the Exporter/Exporting without using Export's import method ########################################################################################################## package Bestiary; @ISA = qw(Exporter); @EXPORT_OK = qw ($zoo); sub import { $Bestiary::zoo = "menagerie"; } -------------- sub import { $Bestiary::zoo = "menagerie"; Bestiary->export_to_level(1, @_); } ############################################################################ 11:Modules/Creating Modules/Module Privacy and the Exporter/Version checking ############################################################################ use Bestiary 3.14; # The Bestiary must be version 3.14 or later use Bestiary v1.0.4; # The Bestiary must be version 1.0.4 or later #################################################################################### 11:Modules/Creating Modules/Module Privacy and the Exporter/Managing unknown symbols #################################################################################### sub export_fail { my $class = shift; carp "Sorry, these symbols are unavailable: @_"; return @_; } ########################################################################################## 11:Modules/Creating Modules/Module Privacy and the Exporter/Tag handling utility functions ########################################################################################## %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]); Exporter::export_tags('foo'); # add aa, bb and cc to @EXPORT Exporter::export_ok_tags('bar'); # add aa, cc and dd to @EXPORT_OK ######################################## 11:Modules/Overriding Built-in Functions ######################################## use subs qw(chdir chroot chmod chown); chdir $somewhere; sub chdir { ... } -------------- *CORE::GLOBAL::glob = sub { my $pat = shift; my @got; local *D; if (opendir D, '.') { @got = grep /$pat/, readdir D; closedir D; } return @got; } package Whatever; print <^[a-z_]+\.pm\$>; # show all pragmas in the current directory ####################################################################### 12:Objects/Method Invocation/Method Invocation Using the Arrow Operator ####################################################################### $mage = Wizard->summon("Gandalf"); # class method $mage->speak("friend"); # instance method -------------- Wizard->summon("Gandalf")->speak("friend"); -------------- $method = "summon"; $mage = Wizard->$method("Gandalf"); # Invoke Wizard->summon $travel = $companion eq "Shadowfax" ? "ride" : "walk"; $mage->$travel("seven leagues"); # Invoke $mage->ride or $mage->walk ##################################################################### 12:Objects/Method Invocation/Method Invocation Using Indirect Objects ##################################################################### $mage = summon Wizard "Gandalf"; $nemesis = summon Balrog home => "Moria", weapon => "whip"; move $nemesis "bridge"; speak $mage "You cannot pass"; break $staff; # safer to use: break $staff (); -------------- print STDERR "help!!!\n"; -------------- speak { summon Wizard "Gandalf" } "friend"; ################################################################### 12:Objects/Method Invocation/Syntactic Snafus with Indirect Objects ################################################################### enchant $sword ($pips + 2) * $cost; -------------- ($sword->enchant($pips + 2)) * $cost; -------------- name $sword $oldname || "Glamdring"; # can't use "or" here! -------------- $sword->name($oldname || "Glamdring"); -------------- speak $mage "friend" && enter(); # should've been "and" here! -------------- $mage->speak("friend" && enter()); -------------- enter() if $mage->speak("friend"); $mage->speak("friend") && enter(); speak $mage "friend" and enter(); -------------- move $party->{LEADER}; # probably wrong! move $riders[$i]; # probably wrong! -------------- $party->move->{LEADER}; $riders->move([$i]); -------------- $party->{LEADER}->move; $riders[$i]->move; ################################################### 12:Objects/Method Invocation/Package-Quoted Classes ################################################### $obj = new ElvenRing; # could be new("ElvenRing") # or even new(ElvenRing()) $obj = ElvenRing->new; # could be ElvenRing()->new() $obj = new ElvenRing::; # always "ElvenRing"->new() $obj = ElvenRing::->new; # always "ElvenRing"->new() -------------- $obj = new ElvenRing:: name => "Narya", owner => "Gandalf", domain => "fire", stone => "ruby"; -------------- use ElvenRing; require ElvenRing; ############################## 12:Objects/Object Construction ############################## $obj = { }; # Get reference to anonymous hash. bless($obj); # Bless hash into current package. bless($obj, "Critter"); # Bless hash into class Critter. -------------- package Critter; sub spawn { bless {}; } -------------- package Critter; sub spawn { my $self = {}; # Reference to an empty anonymous hash bless $self, "Critter"; # Make that hash a Critter object return $self; # Return the freshly generated Critter } -------------- $pet = Critter->spawn; ####################################################### 12:Objects/Object Construction/Inheritable Constructors ####################################################### -------------- sub spawn { my $class = shift; # Store the package name my $self = { }; bless($self, $class); # Bless the reference into that package return $self; } -------------- $vermin = Critter->spawn; $shelob = Spider->spawn; -------------- $type = "Spider"; $shelob = $type->spawn; # same as "Spider"->spawn -------------- sub spawn { my $invocant = shift; my $class = ref($invocant) || $invocant; # Object or class name my $self = { }; bless($self, $class); return $self; } ########################################### 12:Objects/Object Construction/Initializers ########################################### $steed = Horse->new(name => "Shadowfax", color => "white"); -------------- sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = { @_ }; # Remaining args become attributes bless($self, $class); # Bestow objecthood return $self; } -------------- sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = { color => "bay", legs => 4, owner => undef, @_, # Override previous attributes }; return bless $self, $class; } $ed = Horse->new; # A 4-legged bay horse $stallion = Horse->new(color => "black"); # A 4-legged black horse -------------- $steed = Horse->new(color => "dun"); $foal = $steed->clone(owner => "EquuGen Guild, Ltd."); sub clone { my $model = shift; my $self = $model->new(%$model, @_); return $self; # Previously blessed by ->new } ############################ 12:Objects/Class Inheritance ############################ package Horse; our @ISA = "Critter"; -------------- $steed->move(10); ######################################################## 12:Objects/Class Inheritance/Inheritance through C<@ISA> ######################################################## package Mule; our @ISA = ("Horse", "Donkey"); -------------- package Mule; use base ("Horse", "Donkey"); # declare superclasses -------------- package Mule; BEGIN { our @ISA = ("Horse", "Donkey"); require Horse; require Donkey; } ######################################################### 12:Objects/Class Inheritance/Accessing Overridden Methods ######################################################### $stallion = Horse->new(gender => "male"); $molly = Mule->new(gender => "female"); $colt = $molly->breed($stallion); -------------- $colt = Horse::breed($molly, $stallion); -------------- $colt = $molly->Horse::breed($stallion); -------------- package Mule; our @ISA = qw(Horse Donkey); sub kick { my $self = shift; print "The mule kicks!\n"; $self->SUPER::kick(@_); } -------------- sub speak { my $self = shift; print "The mule speaks!\n"; $self->Donkey::speak(@_); } -------------- package Bird; use Dragonfly; sub Dragonfly::divebomb { shift->SUPER::divebomb(@_) } -------------- package Bird; use Dragonfly; { package Dragonfly; sub divebomb { shift->SUPER::divebomb(@_) } } ################################################################### 12:Objects/Class Inheritance/UNIVERSAL: The Ultimate Ancestor Class ################################################################### use FileHandle; if (FileHandle->isa("Exporter")) { print "FileHandle is an Exporter.\n"; } $fh = FileHandle->new(); if ($fh->isa("IO::Handle")) { print "\$fh is some sort of IOish object.\n"; } if ($fh->isa("GLOB")) { print "\$fh is really a GLOB.\n"; } -------------- if ($invocant->can("copy")) { print "Our invocant can copy.\n"; } -------------- $obj->snarl if $obj->can("snarl"); -------------- sub snarl { my $self = shift; print "Snarling: @_\n"; my %seen; for my $parent (@ISA) { if (my $code = $parent->can("snarl")) { $self->$code(@_) unless $seen{$code}++; } } } -------------- use Thread 1.0; # calls Thread->VERSION(1.0) print "Running version ", Thread->VERSION, " of Thread.\n"; -------------- use Data::Dumper; use Carp; sub UNIVERSAL::copy { my $self = shift; if (ref $self) { return eval Dumper($self); # no CODE refs } else { confess "UNIVERSAL::copy can't copy class $self"; } } ############################################### 12:Objects/Class Inheritance/Method Autoloading ############################################### sub AUTOLOAD { return if our $AUTOLOAD =~ /::DESTROY$/; ... } -------------- if ($obj->can("methname") || $obj->can("AUTOLOAD")) { $obj->methname(); } -------------- package Goblin; sub kick; sub bite; sub scratch; -------------- package Goblin; use subs qw(kick bite scratch); ############################################ 12:Objects/Class Inheritance/Private Methods ############################################ # declare private method my $secret_door = sub { my $self = shift; .... }; -------------- sub knock { my $self = shift; if ($self->{knocked}++ > 5) { $self->$secret_door(); } } ############################### 12:Objects/Instance Destructors ############################### package MailNotify; sub DESTROY { my $self = shift; my $fh = $self->{mailhandle}; my $id = $self->{name}; print $fh "\n$id is signing off at " . localtime() . "\n"; close $fh; # close pipe to mailer } -------------- sub DESTROY { my $self = shift; # check for an overridden destructor... $self->SUPER::DESTROY if $self->can("SUPER::DESTROY"); # now do your own thing before or after } ################################# 12:Objects/Managing Instance Data ################################# sub get_name { my $self = shift; return $self->{name}; } sub set_name { my $self = shift; $self->{name} = shift; } -------------- $him = Person->new(); $him->set_name("Frodo"); $him->set_name( ucfirst($him->get_name) ); -------------- sub name { my $self = shift; if (@_) { $self->{name} = shift } return $self->{name}; } -------------- $him = Person->new(); $him->name("Frodo"); $him->name( ucfirst($him->name) ); -------------- sub name { my $self = shift; my $field = __PACKAGE__ . "::name"; if (@_) { $self->{$field} = shift } return $self->{$field}; } ####################################################################### 12:Objects/Managing Instance Data/Field Declarations with C ####################################################################### sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; return bless [], $class; } -------------- sub name { my $self = shift; if (@_) { $self->[0] = shift } return $self->[0]; } sub race { my $self = shift; if (@_) { $self->[1] = shift } return $self->[1]; } sub aliases { my $self = shift; if (@_) { $self->[2] = shift } return $self->[2]; } -------------- package Person; use fields qw(name race aliases); -------------- package Person; use fields qw(name race aliases); sub new { my $type = shift; my Person $self = fields::new(ref $type || $type); $self->{name} = "unnamed"; $self->{race} = "unknown; $self->{aliases} = []; return $self; } sub name { my Person $self = shift; $self->{name} = shift if @_; return $self->{name}; } sub race { my Person $self = shift; $self->{race} = shift if @_; return $self->{race}; } sub aliases { my Person $self = shift; $self->{aliases} = shift if @_; return $self->{aliases}; } 1; -------------- package Wizard; use base "Person"; use fields qw(staff color sphere); -------------- my Wizard $mage = fields::new("Wizard"); -------------- $mage->name("Gandalf"); $mage->color("Grey"); -------------- $mage->{name} = "Gandalf"; $mage->{color} = "Grey"; ########################################################################## 12:Objects/Managing Instance Data/Generating Classes with C ########################################################################## package Person; use Class::Struct; struct Person => { # create a definition for a "Person" name => '$', # name field is a scalar race => '$', # race field is also a scalar aliases => '@', # but aliases field is an array ref }; 1; -------------- use Person; my $mage = Person->new(); $mage->name("Gandalf"); $mage->race("Istar"); $mage->aliases( ["Mithrandir", "Olorin", "Incanus"] ); ####################################################################### 12:Objects/Managing Instance Data/Generating Accessors with Autoloading ####################################################################### use Person; $him = Person->new; $him->name("Aragorn"); $him->race("Man"); $him->aliases( ["Strider", "Estel", "Elessar"] ); printf "%s is of the race of %s.\n", $him->name, $him->race; print "His aliases are: ", join(", ", @{$him->aliases}), ".\n"; -------------- package Person; use Carp; my %fields = ( "Person::name" => "unnamed", "Person::race" => "unknown", "Person::aliases" => [], ); # The next declaration guarantees we get our own autoloader. use subs qw(name race aliases); sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $self = { %fields, @_ }; # clone like Class::Struct bless $self, $class; return $self; } sub AUTOLOAD { my $self = shift; # only handle instance methods, not class methods croak "$self not an object" unless ref($invocant); my $name = our $AUTOLOAD; return if $name =~ /::DESTROY$/; unless (exists $self->{$name}) { croak "Can't access `$name' field in $self"; } if (@_) { return $self->{$name} = shift } else { return $self->{$name} } } #################################################################### 12:Objects/Managing Instance Data/Generating Accessors with Closures #################################################################### package Person; sub new { my $invocant = shift; my $self = bless({}, ref $invocant || $invocant); $self->init(); return $self; } sub init { my $self = shift; $self->name("unnamed"); $self->race("unknown"); $self->aliases([]); } for my $field (qw(name race aliases)) { my $slot = __PACKAGE__ . "::$field"; no strict "refs"; # So symbolic ref to typeglob works. *$field = sub { my $self = shift; $self->{$slot} = shift if @_; return $self->{$slot}; }; } #################################################################### 12:Objects/Managing Instance Data/Using Closures for Private Objects #################################################################### package Person; sub new { my $invocant = shift; my $class = ref($invocant) || $invocant; my $data = { NAME => "unnamed", RACE => "unknown", ALIASES => [], }; my $self = sub { my $field = shift; ############################# ### ACCESS CHECKS GO HERE ### ############################# if (@_) { $data->{$field} = shift } return $data->{$field}; }; bless($self, $class); return $self; } # generate method names for my $field (qw(name race aliases)) { no strict "refs"; # for access to the symbol table *$field = sub { my $self = shift; return $self->(uc $field, @_); }; } -------------- use Carp; local $Carp::CarpLevel = 1; # Keeps croak messages short my ($cpack, $cfile) = caller(); -------------- croak "No valid field `$field' in object" unless exists $data->{$field}; -------------- carp "Unmediated access denied to foreign file" unless $cfile eq __FILE__; -------------- carp "Unmediated access denied to foreign package ${cpack}::" unless $cpack eq __PACKAGE__; -------------- carp "Unmediated access denied to unfriendly class ${cpack}::" unless $cpack->isa(__PACKAGE__); ############################################ 12:Objects/Managing Instance Data/New Tricks ############################################ package Critter; sub new { my $class = shift; my $self = { pups => 0, @_ }; # Override default. bless $self, $class; } sub pups : lvalue { # We'll assign to pups() later. my $self = shift; $self->{pups}; } package main; $varmint = Critter->new(pups => 4); $varmint->pups *= 2; # Assign to $varmint->pups! $varmint->pups =~ s/(.)/$1$1/; # Modify $varmint->pups in place! print $varmint->pups; # Now we have 88 pups. -------------- sub pups : locked method { ... } ############################## 12:Objects/Managing Class Data ############################## Critter->population() # Access via class name $gollum->population() # Access via instance -------------- package Critter; our $Population = 0; sub population { return $Population; } sub DESTROY { $Population-- } sub spawn { my $invocant = shift; my $class = ref($invocant) || $invocant; $Population++; return bless { name => shift || "anon" }, $class; } sub name { my $self = shift; $self->{name} = shift if @_; return $self->{name}; } -------------- our $Debugging = 0; # class datum sub debug { shift; # intentionally ignore invocant $Debugging = shift if @_; return $Debugging; } -------------- { my $Debugging = 0; # lexically scoped class datum sub debug { shift; # intentionally ignore invocant $Debugging = shift if @_; return $Debugging; } } -------------- sub debug { my $invocant = shift; my $class = ref($invocant) || $invocant; my $varname = $class . "::Debugging"; no strict "refs"; # to access package data symbolically $$varname = shift if @_; return $$varname; } ############## 13:Overloading ############## print $object->as_string; $new_object = $subject->add($object); -------------- print $object; $new_object = $subject + $object; ##################################### 13:Overloading/The C Pragma ##################################### package MyClass; use overload '+' => \&myadd, # coderef '<' => "less_than"; # named method 'abs' => sub { return @_ }, # anonymous subroutine ################################ 13:Overloading/Overload Handlers ################################ package ClipByte; use overload '+' => \&clip_add, '-' => \&clip_sub; sub new { my $class = shift; my $value = shift; return bless \$value => $class; } sub clip_add { my ($x, $y) = @_; my ($value) = ref($x) ? $$x : $x; $value += ref($y) ? $$y : $y; $value = 255 if $value > 255; $value = 0 if $value < 0; return bless \$value => ref($x); } sub clip_sub { my ($x, $y, $swap) = @_; my ($value) = (ref $x) ? $$x : $x; $value -= (ref $y) ? $$y : $y; if ($swap) { $value = -$value } $value = 255 if $value > 255; $value = 0 if $value < 0; return bless \$value => ref($x); } package main; $byte1 = ClipByte->new(200); $byte2 = ClipByte->new(100); $byte3 = $byte1 + $byte2; # 255 $byte4 = $byte1 - $byte2; # 100 $byte5 = 150 - $byte2; # 50 ##################################### 13:Overloading/Overloadable Operators ##################################### package Person; use overload q("") => \&as_string; sub new { my $class = shift; return bless { @_ } => $class; } sub as_string { my $self = shift; my ($key, $value, $result); while (($key, $value) = each %$self) { $result .= "$key => $value\n"; } return $result; } $obj = Person->new(height => 72, weight => 165, eyes => "brown"); print $obj; -------------- package ShiftString; use overload '>>' => \&right_shift, '""' => sub { ${ $_[0] } }; sub new { my $class = shift; my $value = shift; return bless \$value => $class; } sub right_shift { my ($x, $y) = @_; my $value = $$x; substr($value, -$y) = ""; return bless \$value => ref($x); } $camel = ShiftString->new("Camel"); $ram = $camel >> 2; print $ram; # Cam -------------- package MagicDec; use overload q(--) => \&decrement, q("") => sub { ${ $_[0] } }; sub new { my $class = shift; my $value = shift; bless \$value => $class; } sub decrement { my @string = reverse split(//, ${ $_[0] } ); my $i; for ($i = 0; $i < @string; $i++ ) { last unless $string[$i] =~ /a/i; $string[$i] = chr( ord($string[$i]) + 25 ); } $string[$i] = chr( ord($string[$i]) - 1 ); my $result = join('', reverse @string); $_[0] = bless \$result => ref($_[0]); } package main; for $normal (qw/perl NZ Pa/) { $magic = MagicDec->new($normal); $magic--; print "$normal goes to $magic\n"; } -------------- package LuckyDraw; use overload '<>' => sub { my $self = shift; return splice @$self, rand @$self, 1; }; sub new { my $class = shift; return bless [@_] => $class; } package main; $lotto = new LuckyDraw 1 .. 51; for (qw(1st 2nd 3rd 4th 5th 6th)) { $lucky_number = <$lotto>; print "The $_ lucky number is: $lucky_number.\n"; } $lucky_number = <$lotto>; print "\nAnd the bonus number is: $lucky_number.\n"; -------------- package PsychoHash; use overload '%{}' => \&as_hash; sub as_hash { my ($x) = shift; return { @$x }; } sub new { my $class = shift; return bless [ @_ ] => $class; } $critter = new PsychoHash( height => 72, weight => 365, type => "camel" ); print $critter->{weight}; # prints 365 -------------- use overload '+' => sub { bless [ \$_[0], \$_[1] ] }; ########################################## 13:Overloading/The Copy Constructor (C<=>) ########################################## $copy = $scalar_ref; ++$$copy; # changes $$scalar_ref -------------- $copy = $scalar_ref; $copy = $copy + 1; -------------- $copy = $scalar_ref; ... ++$copy; -------------- $copy = $scalar_ref; ... $copy = $copy->clone(undef, ""); $copy->incr(undef, ""); #################################### 13:Overloading/Overloading Constants #################################### sub import { overload::constant ( integer => \&integer_handler, float => \&float_handler, binary => \&oct_and_hex_handler, q => \&string_handler, qr => \®ex_handler ) } -------------- $year = cube(12) + 1; $pi = 3.14159265358979; -------------- package DigitDoubler; # A module to be placed in DigitDoubler.pm use overload; sub import { overload::constant ( integer => \&integer_handler, float => \&float_handler ) } sub integer_handler { my ($orig, $interp, $context) = @_; return $interp * 2; # double all constant integers } 1; -------------- use DigitDoubler; $trouble = 123; # trouble is now 246 ################################### 13:Overloading/Run-time Overloading ################################### eval " use overload '+' => \&my_add "; -------------- eval " no overload '+', '--', '<=' "; ############################### 14:Tied Variables/Tying Scalars ############################### #!/usr/bin/perl package Centsible; sub TIESCALAR { bless \my $self, shift } sub STORE { ${ $_[0] } = $_[1] } # do the default thing sub FETCH { sprintf "%.02f", ${ my $self = shift } } # round value package main; tie $bucks, "Centsible"; $bucks = 45.00; $bucks *= 1.0715; # tax $bucks *= 1.0715; # and double tax! print "That will be $bucks, please.\n"; #################################################### 14:Tied Variables/Tying Scalars/Scalar Tying Methods #################################################### use ScalarFile; # load ScalarFile.pm tie $camel, "ScalarFile", "/tmp/camel.lot"; -------------- $dromedary = $camel; -------------- $dromedary = (tied $camel)->FETCH(): -------------- $clot = tie $camel, "ScalarFile", "/tmp/camel.lot"; $dromedary = $camel; # through the implicit interface $dromedary = $clot->FETCH(); # same thing, but explicitly -------------- package ScalarFile; use Carp; # Propagates error messages nicely. use strict; # Enforce some discipline on ourselves. use warnings; # Turn on lexically scoped warnings. use warnings::register; # Allow user to say "use warnings 'ScalarFile'". my $count = 0; # Internal count of tied ScalarFiles. -------------- sub TIESCALAR { # in ScalarFile.pm my $class = shift; my $filename = shift; $count++; # A file-scoped lexical, private to class. return bless \$filename, $class; } -------------- sub TIESCALAR { bless \$_[1], $_[0] } # WRONG, could refer to global. -------------- sub TIESCALAR { # in ScalarFile.pm my $class = shift; my $filename = shift; my $fh; if (open $fh, "<", $filename or open $fh, ">", $filename) { close $fh; $count++; return bless \$filename, $class; } carp "Can't tie $filename: $!" if warnings::enabled(); return; } -------------- tie ($string, "ScalarFile", "camel.lot") or die; -------------- sub FETCH { my $self = shift; confess "I am not a class method" unless ref $self; return unless open my $fh, $$self; read($fh, my $value, -s $fh); # NB: don't use -s on pipes! return $value; } -------------- tie($string, "ScalarFile", "camel.lot"); print $string; -------------- sub STORE { my($self,$value) = @_; ref $self or confess "not a class method"; open my $fh, ">", $$self or croak "can't clobber $$self: $!"; syswrite($fh, $value) == length $value or croak "can't write to $$self: $!"; close $fh or croak "can't close $$self: $!"; return $value; } -------------- tie($string, "ScalarFile", "camel.lot"); $string = "Here is the first line of camel.lot\n"; $string .= "And here is another line, automatically appended.\n"; -------------- sub DESTROY { my $self = shift; confess "wrong type" unless ref $self; $count--; } -------------- sub count { # my $invocant = shift; $count; } -------------- if (ScalarFile->count) { warn "Still some tied ScalarFiles sitting around somewhere...\n"; } ######################################################### 14:Tied Variables/Tying Scalars/Magical Counter Variables ######################################################### tie my $counter, "Tie::Counter", 100; @array = qw /Red Green Blue/; for my $color (@array) { # Prints: print " $counter $color\n"; # 100 Red } # 101 Green # 102 Blue -------------- package Tie::Counter; sub FETCH { ++ ${ $_[0] } } sub STORE { ${ $_[0] } = $_[1] } sub TIESCALAR { my ($class, $value) = @_; $value = 0 unless defined $value; bless \$value => $class; } 1; # if in module ######################################################### 14:Tied Variables/Tying Scalars/Magically Banishing C<$_> ######################################################### no Underscore; -------------- #!/usr/bin/perl no Underscore; @tests = ( "Assignment" => sub { $_ = "Bad" }, "Reading" => sub { print }, "Matching" => sub { $x = /badness/ }, "Chop" => sub { chop }, "Filetest" => sub { -x }, "Nesting" => sub { for (1..3) { print } }, ); while ( ($name, $code) = splice(@tests, 0, 2) ) { print "Testing $name: "; eval { &$code }; print $@ ? "detected" : " missed!"; print "\n"; } -------------- package Underscore; use Carp; sub TIESCALAR { bless \my $dummy => shift } sub FETCH { croak 'Read access to $_ forbidden' } sub STORE { croak 'Write access to $_ forbidden' } sub unimport { tie($_, __PACKAGE__) } sub import { untie $_ } tie($_, __PACKAGE__) unless tied $_; 1; ############################## 14:Tied Variables/Tying Arrays ############################## #!/usr/bin/perl package ClockArray; use Tie::Array; our @ISA = 'Tie::StdArray'; sub FETCH { my($self,$place) = @_; $self->[ $place % 12 ]; } sub STORE { my($self,$place,$value) = @_; $self->[ $place % 12 ] = $value; } package main; tie my @array, 'ClockArray'; @array = ( "a" ... "z" ); print "@array\n"; ################################################## 14:Tied Variables/Tying Arrays/Array Tying Methods ################################################## use BoundedArray; tie @array, "BoundedArray", 2; $array[0] = "fine"; $array[1] = "good"; $array[2] = "great"; $array[3] = "whoa"; # Prohibited; displays an error message. -------------- package BoundedArray; use Carp; use strict; -------------- use Tie::Array; our @ISA = ("Tie::Array"); -------------- sub TIEARRAY { my $class = shift; my $bound = shift; confess "usage: tie(\@ary, 'BoundedArray', max_subscript)" if @_ || $bound =~ /\D/; return bless { BOUND => $bound, DATA => [] }, $class; } -------------- tie(@array, "BoundedArray", 3); # maximum allowable index is 3 -------------- sub FETCH { my ($self, $index) = @_; if ($index > $self->{BOUND}) { confess "Array OOB: $index > $self->{BOUND}"; } return $self->{DATA}[$index]; } -------------- sub STORE { my($self, $index, $value) = @_; if ($index > $self->{BOUND} ) { confess "Array OOB: $index > $self->{BOUND}"; } return $self->{DATA}[$index] = $value; } -------------- sub FETCHSIZE { my $self = shift; return scalar @{$self->{DATA}}; } -------------- sub STORESIZE { my ($self, $count) = @_; if ($count > $self->{BOUND}) { confess "Array OOB: $count > $self->{BOUND}"; } $#{$self->{DATA}} = $count; } -------------- sub EXISTS { my ($self, $index) = @_; if ($index > $self->{BOUND}) { confess "Array OOB: $index > $self->{BOUND}"; } exists $self->{DATA}[$index]; } -------------- sub DELETE { my ($self, $index) = @_; print STDERR "deleting!\n"; if ($index > $self->{BOUND}) { confess "Array OOB: $index > $self->{BOUND}"; } delete $self->{DATA}[$index]; } -------------- sub CLEAR { my $self = shift; $self->{DATA} = []; } -------------- tie(@array, "BoundedArray", 2); @array = (1, 2, 3, 4); -------------- sub PUSH { my $self = shift; if (@_ + $#{$self->{DATA}} > $self->{BOUND}) { confess "Attempt to push too many elements"; } push @{$self->{DATA}}, @_; } -------------- sub POP { my $self = shift; pop @{$self->{DATA}} } ##################################################### 14:Tied Variables/Tying Arrays/Notational Convenience ##################################################### #!/usr/bin/perl package RandInterp; sub TIEARRAY { bless \my $self }; sub FETCH { int rand $_[1] }; package main; tie @rand, "RandInterp"; for (1,10,100,1000) { print "A random integer less than $_ would be $rand[$_]\n"; } $rand[32] = 5; # Will this reformat our system disk? ############################## 14:Tied Variables/Tying Hashes ############################## $h{$k} = "one"; $h{$k} = "two"; -------------- push @{ $h{$k} }, "one"; push @{ $h{$k} }, "two"; -------------- package Tie::AppendHash; use Tie::Hash; our @ISA = ("Tie::StdHash"); sub STORE { my ($self, $key, $value) = @_; push @{$self->{key}}, $value; } 1; ################################################# 14:Tied Variables/Tying Hashes/Hash Tying Methods ################################################# use DotFiles; tie %dot, "DotFiles"; if ( $dot{profile} =~ /MANPATH/ or $dot{login} =~ /MANPATH/ or $dot{cshrc} =~ /MANPATH/ ) { print "you seem to set your MANPATH\n"; } -------------- # Third argument is the name of a user whose dot files we will tie to. tie %him, "DotFiles", "daemon"; foreach $f (keys %him) { printf "daemon dot file %s is size %d\n", $f, length $him{$f}; } -------------- package DotFiles; use Carp; sub whowasi { (caller(1))[3] . "()" } my $DEBUG = 0; sub debug { $DEBUG = @_ ? shift : 1 } -------------- sub TIEHASH { my $self = shift; my $user = shift || $>; my $dotdir = shift || ""; croak "usage: @{[ &whowasi ]} [USER [DOTDIR]]" if @_; $user = getpwuid($user) if $user =~ /^\d+$/; my $dir = (getpwnam($user))[7] or croak "@{ [&whowasi] }: no user $user"; $dir .= "/$dotdir" if $dotdir; my $node = { USER => $user, HOME => $dir, CONTENTS => {}, CLOBBER => 0, }; opendir DIR, $dir or croak "@{[&whowasi]}: can't opendir $dir: $!"; for my $dot ( grep /^\./ && -f "$dir/$_", readdir(DIR)) { $dot =~ s/^\.//; $node->{CONTENTS}{$dot} = undef; } closedir DIR; return bless $node, $self; } -------------- sub FETCH { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift; my $dir = $self->{HOME}; my $file = "$dir/.$dot"; unless (exists $self->{CONTENTS}->{$dot} || -f $file) { carp "@{[&whowasi]}: no $dot file" if $DEBUG; return undef; } # Implement a cache. if (defined $self->{CONTENTS}->{$dot}) { return $self->{CONTENTS}->{$dot}; } else { return $self->{CONTENTS}->{$dot} = `cat $dir/.$dot`; } } -------------- sub STORE { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift; my $value = shift; my $file = $self->{HOME} . "/.$dot"; croak "@{[&whowasi]}: $file not clobberable" unless $self->{CLOBBER}; open(F, "> $file") or croak "can't open $file: $!"; print F $value; close(F); } -------------- $ob = tie %daemon_dots, "daemon"; $ob->clobber(1); $daemon_dots{signature} = "A true daemon\n"; -------------- tie %daemon_dots, "DotFiles", "daemon"; tied(%daemon_dots)->clobber(1); -------------- (tie %daemon_dots, "DotFiles", "daemon")->clobber(1); -------------- sub clobber { my $self = shift; $self->{CLOBBER} = @_ ? shift : 1; } -------------- sub DELETE { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift; my $file = $self->{HOME} . "/.$dot"; croak "@{[&whowasi]}: won't remove file $file" unless $self->{CLOBBER}; delete $self->{CONTENTS}->{$dot}; unlink $file or carp "@{[&whowasi]}: can't unlink $file: $!"; } -------------- sub CLEAR { carp &whowasi if $DEBUG; my $self = shift; croak "@{[&whowasi]}: won't remove all dotfiles for $self->{USER}" unless $self->{CLOBBER} > 1; for my $dot ( keys %{$self->{CONTENTS}}) { $self->DELETE($dot); } } -------------- sub EXISTS { carp &whowasi if $DEBUG; my $self = shift; my $dot = shift; return exists $self->{CONTENTS}->{$dot}; } -------------- sub FIRSTKEY { carp &whowasi if $DEBUG; my $self = shift; my $temp = keys %{$self->{CONTENTS}}; return scalar each %{$self->{CONTENTS}}; } -------------- sub NEXTKEY { carp &whowasi if $DEBUG; my $self = shift; return scalar each %{ $self->{CONTENTS} } } -------------- sub DESTROY { carp &whowasi if $DEBUG; } ################################### 14:Tied Variables/Tying Filehandles ################################### package ReversePrint; use strict; sub TIEHANDLE { my $class = shift; bless [], $class; } sub PRINT { my $self = shift; push @$self, join '', @_; } sub PRINTF { my $self = shift; my $fmt = shift; push @$self, sprintf $fmt, @_; } sub READLINE { my $self = shift; pop @$self; } package main; my $m = "--MORE--\n"; tie *REV, "ReversePrint"; # Do some prints and printfs. print REV "The fox is now dead.$m"; printf REV <<"END", int rand 10000000; The quick brown fox jumps over over the lazy dog %d times! END print REV <<"END"; The quick brown fox jumps over the lazy dog. END # Now read back from the same handle. print while ; ############################################################ 14:Tied Variables/Tying Filehandles/Filehandle Tying Methods ############################################################ package Shout; use Carp; # So we can croak our errors -------------- sub TIEHANDLE { my $class = shift; my $form = shift; open my $self, $form, @_ or croak "can't open $form@_: $!"; if ($form =~ />/) { print $self "\n"; $$self->{WRITING} = 1; # Remember to do end tag } return bless $self, $class; # $fh is a glob ref } -------------- sub PRINT { my $self = shift; print $self map {uc} @_; } -------------- sub READLINE { my $self = shift; return <$self>; } -------------- sub GETC { my $self = shift; return getc($self); } -------------- sub OPEN { my $self = shift; my $form = shift; my $name = "$form@_"; $self->CLOSE; open($self, $form, @_) or croak "can't reopen $name: $!"; if ($form =~ />/) { print $self "\n" or croak "can't start print: $!"; $$self->{WRITING} = 1; # Remember to do end tag } else { $$self->{WRITING} = 0; # Remember not to do end tag } return 1; } -------------- sub CLOSE { my $self = shift; if ($$self->{WRITING}) { $self->SEEK(0, 2) or return; $self->PRINT("\n") or return; } return close $self; } -------------- sub SEEK { my $self = shift; my ($offset, $whence) = @_; return seek($self, $offset, $whence); } -------------- sub TELL { my $self = shift; return tell $self; } -------------- sub PRINTF { my $self = shift; my $template = shift; return $self->PRINT(sprintf $template, @_); } -------------- sub READ { my ($self, undef, $length, $offset) = @_; my $bufref = \$_[1]; return read($self, $$bufref, $length, $offset); } -------------- sub WRITE { my $self = shift; my $string = uc(shift); my $length = shift || length $string; my $offset = shift || 0; return syswrite $self, $string, $length, $offset; } -------------- sub EOF { my $self = shift; return eof $self; } -------------- sub BINMODE { my $self = shift; my $disc = shift || ":raw"; return binmode $self, $disc; } -------------- sub BINMODE { croak("Too late to use binmode") } -------------- sub FILENO { my $self = shift; return fileno $self; } -------------- sub DESTROY { my $self = shift; $self->CLOSE; # Close the file using Shout's CLOSE method. } -------------- #!/usr/bin/perl use Shout; tie(*FOO, Shout::, ">filename"); print FOO "hello\n"; # Prints HELLO. seek FOO, 0, 0; # Rewind to beginning @lines = ; # Calls the READLINE method close FOO; # Close file explicitly open(FOO, "+<", "filename"); # Reopen FOO, calling OPEN seek(FOO, 8, 0); # Skip the "\n". sysread(FOO, $inbuf, 5); # Read 5 bytes from FOO into $inbuf print "found $inbuf\n"; # Should print "hello". seek(FOO, -5, 1); # Back up over the "hello". syswrite(FOO, "ciao!\n", 6); # Write 6 bytes into FOO. untie(*FOO); # Calls the CLOSE method implicitly. -------------- # This is just so entirely cool! use overload q("") => sub { $_[0]->pathname }; # This is the stub to put in each function you want to trace. sub trace { my $self = shift; local $Carp::CarpLevel = 1; Carp::cluck("\ntrace magical method") if $self->debug; } # Overload handler to print out our path. sub pathname { my $self = shift; confess "i am not a class method" unless ref $self; $$self->{PATHNAME} = shift if @_; return $$self->{PATHNAME}; } # Dual moded. sub debug { my $self = shift; my $var = ref $self ? \$$self->{DEBUG} : \our $Debug; $$var = shift if @_; return ref $self ? $$self->{DEBUG} || $Debug : $Debug; } -------------- sub GETC { $_[0]->trace; # NEW my($self) = @_; getc($self); } -------------- sub TIEHANDLE { my $class = shift; my $form = shift; my $name = "$form@_"; # NEW open my $self, $form, @_ or croak "can't open $name: $!"; if ($form =~ />/) { print $self "\n"; $$self->{WRITING} = 1; # Remember to do end tag } bless $self, $class; # $fh is a glob ref $self->pathname($name); # NEW return $self; } sub OPEN { $_[0]->trace; # NEW my $self = shift; my $form = shift; my $name = "$form@_"; # NEW $self->CLOSE; open($self, $form, @_) or croak "can't reopen $name: $!"; $self->pathname($name); # NEW if ($form =~ />/) { print $self "\n" or croak "can't start print: $!"; $$self->{WRITING} = 1; # Remember to do end tag } else { $$self->{WRITING} = 0; # Remember not to do end tag } return 1; } ######################################################## 14:Tied Variables/Tying Filehandles/Creative Filehandles ######################################################## use Tie::Open2; tie *CALC, 'Tie::Open2', "bc -l"; $sum = 2; for (1 .. 7) { print CALC "$sum * $sum\n"; $sum = ; print "$_: $sum"; chomp $sum; } close CALC; -------------- package Tie::Open2; use strict; use Carp; use Tie::Handle; # do not inherit from this! use IPC::Open2; sub TIEHANDLE { my ($class, @cmd) = @_; no warnings 'once'; my @fhpair = \do { local(*RDR, *WTR) }; bless $_, 'Tie::StdHandle' for @fhpair; bless(\@fhpair => $class)->OPEN(@cmd) || die; return \@fhpair; } sub OPEN { my ($self, @cmd) = @_; $self->CLOSE if grep {defined} @{ $self->FILENO }; open2(@$self, @cmd); } sub FILENO { my $self = shift; [ map { fileno $self->[$_] } 0,1 ]; } for my $outmeth ( qw(PRINT PRINTF WRITE) ) { no strict 'refs'; *$outmeth = sub { my $self = shift; $self->[1]->$outmeth(@_); }; } for my $inmeth ( qw(READ READLINE GETC) ) { no strict 'refs'; *$inmeth = sub { my $self = shift; $self->[0]->$inmeth(@_); }; } for my $doppelmeth ( qw(BINMODE CLOSE EOF)) { no strict 'refs'; *$doppelmeth = sub { my $self = shift; $self->[0]->$doppelmeth(@_) && $self->[1]->$doppelmeth(@_); }; } for my $deadmeth ( qw(SEEK TELL)) { no strict 'refs'; *$deadmeth = sub { croak("can't $deadmeth a pipe"); }; } 1; -------------- use strict; package Tie::DevNull; sub TIEHANDLE { my $class = shift; my $fh = local *FH; bless \$fh, $class; } for (qw(READ READLINE GETC PRINT PRINTF WRITE)) { no strict 'refs'; *$_ = sub { return }; } package Tie::DevRandom; sub READLINE { rand() . "\n"; } sub TIEHANDLE { my $class = shift; my $fh = local *FH; bless \$fh, $class; } sub FETCH { rand() } sub TIESCALAR { my $class = shift; bless \my $self, $class; } package Tie::Tee; sub TIEHANDLE { my $class = shift; my @handles; for my $path (@_) { open(my $fh, ">$path") || die "can't write $path"; push @handles, $fh; } bless \@handles, $class; } sub PRINT { my $self = shift; my $ok = 0; for my $fh (@$self) { $ok += print $fh @_; } return $ok == @$self; } -------------- package main; tie *SCATTER, "Tie::Tee", qw(tmp1 - tmp2 >tmp3 tmp4); tie *RANDOM, "Tie::DevRandom"; tie *NULL, "Tie::DevNull"; tie my $randy, "Tie::DevRandom"; for my $i (1..10) { my $line = ; chomp $line; for my $fh (*NULL, *SCATTER){ print $fh "$i: $line $randy\n"; } } ####################################### 14:Tied Variables/A Subtle Untying Trap ####################################### package Remember; sub TIESCALAR { my $class = shift; my $filename = shift; open(my $handle, ">", $filename) or die "Cannot open $filename: $!\n"; print $handle "The Start\n"; bless {FH => $handle, VALUE => 0}, $class; } sub FETCH { my $self = shift; return $self->{VALUE}; } sub STORE { my $self = shift; my $value = shift; my $handle = $self->{FH}; print $handle "$value\n"; $self->{VALUE} = $value; } sub DESTROY { my $self = shift; my $handle = $self->{FH}; print $handle "The End\n"; close $handle; } 1; -------------- use strict; use Remember; my $fred; $x = tie $fred, "Remember", "camel.log"; $fred = 1; $fred = 4; $fred = 5; untie $fred; system "cat camel.log"; -------------- sub comment { my $self = shift; my $message = shift; print { $self->{FH} } $handle $message, "\n"; } -------------- use strict; use Remember; my ($fred, $x); $x = tie $fred, "Remember", "camel.log"; $fred = 1; $fred = 4; comment $x "changing..."; $fred = 5; untie $fred; system "cat camel.log"; -------------- undef $x; untie $fred; ############################# 15:Unicode/Building Character ############################# $locaddr = v127.0.0.1; # Certainly stored as bytes. $oreilly = v204.148.40.9; # Might be stored as bytes or utf8. $badaddr = v2004.148.40.9; # Certainly stored as utf8. ######################################### 15:Unicode/Effects of Character Semantics ######################################### use bytes (); # Load wrappers without importing byte semantics. ... $charlen = length("\x{ffff_ffff}"); # Returns 1. $bytelen = bytes::length("\x{ffff_ffff}"); # Returns 7. -------------- use utf8; $convergence = "☞ ☜"; -------------- use utf8; $人++; # A child is born. -------------- "\N{TENGWAR LETTER SILME NUQUERNA}" =~ /^.$/ -------------- "人" =~ /\w/ -------------- "\N{greek:Iota}" =~ /\p{Lu}/ -------------- "o\N{COMBINING TILDE BELOW}" =~ /\X/ -------------- tr/\0-\x{10ffff}/\0-\xff?/; # utf8 to latin1 char -------------- $x = "\u$word"; # titlecase first letter of $word $x = "\U$word"; # uppercase $word $x = "\l$word"; # lowercase first letter of $word $x = "\L$word"; # lowercase $word -------------- use bytes; $bytelen = length("I do 合氣道."); # 15 bytes no bytes; $charlen = length("I do 合氣道."); # but 9 characters -------------- pack("U*", 1, 20, 300, 4000) eq v1.20.300.4000 -------------- chr(1).chr(20).chr(300).chr(4000) eq v1.20.300.4000 -------------- "☞ ☜" eq reverse "☜ ☞" -------------- % perl -MConfig -le 'print $Config{privlib}' ##################################### 16:Interprocess Communication/Signals ##################################### $SIG{INT} = sub { die "\nOutta here!\n" }; $SIG{ALRM} = sub { die "Your alarm clock went off" }; -------------- sub catch_zap { my $signame = shift; our $shucks++; die "Somebody sent me a SIG$signame!"; } $shucks = 0; $SIG{INT} = 'catch_zap'; # always means &main::catch_zap $SIG{INT} = \&catch_zap; # best strategy $SIG{QUIT} = \&catch_zap; # catch another, too -------------- use sigtrap qw(die INT QUIT); use sigtrap qw(die untrapped normal-signals stack-trace any error-signals); -------------- { local $SIG{INT} = 'IGNORE'; ... # Do whatever you want here, ignoring all SIGINTs. fn(); # SIGINTs ignored inside fn() too! ... # And here. } # Block exit restores previous $SIG{INT} value. fn(); # SIGINTs not ignored inside fn() (presumably). ############################################################### 16:Interprocess Communication/Signals/Signalling Process Groups ############################################################### { local $SIG{HUP} = 'IGNORE'; # exempt myself kill(HUP, -$$); # signal my own process group } -------------- unless (kill 0 => $kid_pid) { warn "something wicked happened to $kid_pid"; } ##################################################### 16:Interprocess Communication/Signals/Reaping Zombies ##################################################### use POSIX ":sys_wait_h"; sub REAPER { 1 until waitpid(-1, WNOHANG) == -1) } -------------- $SIG{CHLD} = \&REAPER; -------------- our $zombies = 0; $SIG{CHLD} = sub { $zombies++ }; sub reaper { my $zombie; our %Kid_Status; # store each exit status $zombies = 0; while (($zombie = waitpid(-1, WNOHANG)) != -1) { $Kid_Status{$zombie} = $?; } } while (1) { reaper() if $zombies; ... } ################################################################ 16:Interprocess Communication/Signals/Timing Out Slow Operations ################################################################ use Fcntl ':flock'; eval { local $SIG{ALRM} = sub { die "alarm clock restart" }; alarm 10; # schedule alarm in 10 seconds eval { flock(FH, LOCK_EX) # a blocking, exclusive lock or die "can't flock: $!"; }; alarm 0; # cancel the alarm }; alarm 0; # race condition protection die if $@ && $@ !~ /alarm clock restart/; # reraise ###################################################### 16:Interprocess Communication/Signals/Blocking Signals ###################################################### use POSIX qw(:signal_h); $sigset = POSIX::SigSet->new; $blockset = POSIX::SigSet->new(SIGINT, SIGQUIT, SIGCHLD); sigprocmask(SIG_BLOCK, $blockset, $sigset) or die "Could not block INT,QUIT,CHLD signals: $!\n"; -------------- sigprocmask(SIG_SETMASK, $sigset) or die "Could not restore INT,QUIT,CHLD signals: $!\n"; ################################################ 16:Interprocess Communication/Files/File locking ################################################ use Fcntl qw(:DEFAULT :flock); open(FH, "< filename") or die "can't open filename: $!"; flock(FH, LOCK_SH) or die "can't lock filename: $!"; # now read from FH -------------- flock(FH, LOCK_SH | LOCK_NB) or die "can't lock filename: $!"; -------------- use Fcntl qw(:DEFAULT :flock); open(FH, "< filename") or die "can't open filename: $!"; unless (flock(FH, LOCK_SH | LOCK_NB)) { local $| = 1; print "Waiting for lock on filename..."; flock(FH, LOCK_SH) or die "can't lock filename: $!"; print "got it.\n" } # now read from FH -------------- use Fcntl qw(:DEFAULT :flock); sysopen(FH, "filename", O_WRONLY | O_CREAT) or die "can't open filename: $!"; flock(FH, LOCK_EX) or die "can't lock filename: $!"; truncate(FH, 0) or die "can't truncate filename: $!"; # now write to FH -------------- use Fcntl qw(:DEFAULT :flock); sysopen(FH, "counterfile", O_RDWR | O_CREAT) or die "can't open counterfile: $!"; flock(FH, LOCK_EX) or die "can't write-lock counterfile: $!"; $counter = || 0; # first time would be undef seek(FH, 0, 0) or die "can't rewind counterfile : $!"; print FH $counter+1, "\n" or die "can't write counterfile: $!"; # next line technically superfluous in this program, but # a good idea in the general case truncate(FH, tell(FH)) or die "can't truncate counterfile: $!"; close(FH) or die "can't close counterfile: $!"; -------------- use Fcntl qw(:DEFAULT :flock); use DB_File; # demo purposes only; any db is fine $DBNAME = "/path/to/database"; $LCK = $DBNAME . ".lockfile"; # use O_RDWR if you expect to put data in the lockfile sysopen(DBLOCK, $LCK, O_RDONLY | O_CREAT) or die "can't open $LCK: $!"; # must get lock before opening database flock(DBLOCK, LOCK_EX) or die "can't LOCK_SH $LCK: $!"; tie(%hash, "DB_File", $DBNAME, O_RDWR | O_CREAT) or die "can't tie $DBNAME: $!"; -------------- untie %hash; # must close database before lockfile close DBLOCK; # safe to let go of lock now ######################################################## 16:Interprocess Communication/Files/Passing Filehandles ######################################################## open(INPUT, "< /etc/motd") or die "/etc/motd: $!"; if ($pid = fork) { waitpid($pid,0) } else { defined($pid) or die "fork: $!"; while () { print "$.: $_" } exit; # don't let child fall back into main code } # INPUT handle now at EOF in parent -------------- open(INPUT, "< /etc/motd") or die "/etc/motd: $!"; if ($pid = fork) { wait } else { defined($pid) or die "fork: $!"; open(STDIN, "<&INPUT") or die "dup: $!"; exec("cat", "-n") or die "exec cat: $!"; } -------------- # open file and mark INPUT to be left open across execs { local $^F = 10_000; open(INPUT, "< /etc/motd") or die "/etc/motd: $!"; } # old value of $^F restored on scope exit -------------- if ($pid = fork) { wait } else { defined($pid) or die "fork: $!"; $fdfile = "/dev/fd/" . fileno(INPUT); exec("cat", "-n", $fdfile) or die "exec cat: $!"; } -------------- use Fcntl qw/F_SETFD/; fcntl(INPUT, F_SETFD, 0) or die "Can't clear close-on-exec flag on INPUT: $!\n"; -------------- fcntl(INPUT, F_SETFD, 1) or die "Can't set close-on-exec flag on INPUT: $!\n"; -------------- use Fcntl qw/F_SETFD F_GETFD/; printf("INPUT will be %s across execs\n" fcntl(INPUT, F_GETFD, 1) ? "closed" : "left open"); -------------- if (defined($ENV{input_fdno}) && $ENV{input_fdno}) =~ /^\d$/) { open(INPUT, "<&=$ENV{input_fdno}") or die "can't fdopen $ENV{input_fdno} for input: $!"; } -------------- #!/usr/bin/perl -p # nl - number input lines printf "%6d ", $.; -------------- $fdspec = '<&=' . fileno(INPUT); system("nl", $fdspec); -------------- @lines = `nl '$fdspec'`; # protect spec from shell ################################################### 16:Interprocess Communication/Pipes/Anonymous Pipes ################################################### open SPOOLER, "| cat -v | lpr -h 2>/dev/null" or die "can't fork: $!"; local $SIG{PIPE} = sub { die "spooler pipe broke" }; print SPOOLER "stuff\n"; close SPOOLER or die "bad spool: $! $?"; -------------- open SPOOLER, "|-", "lpr", "-h" or die "can't run lpr: $!"; -------------- if (-t STDOUT) { # only if stdout is a terminal my $pager = $ENV{PAGER} || 'more'; open(STDOUT, "| $pager") or die "can't fork a pager: $!"; } END { close(STDOUT) or die "can't close STDOUT: $!" } -------------- open STATUS, "netstat -an 2>/dev/null |" or die "can't fork: $!"; while () { next if /^(tcp|udp)/; print; } close STATUS or die "bad netstat: $! $?"; -------------- open STATUS, "-|", "netstat", "-an" or die "can't run netstat: $!"; -------------- print grep { !/^(tcp|udp)/ } `netstat -an 2>&1`; die "bad netstat" if $?; ####################################################### 16:Interprocess Communication/Pipes/Talking to Yourself ####################################################### if (open(TO, "|-")) { print TO $fromparent; } else { $tochild = ; exit; } -------------- if (open(FROM, "-|")) { $toparent = ; } else { print STDOUT $fromchild; exit; } -------------- tee("/tmp/foo", "/tmp/bar", "/tmp/glarch"); while (<>) { print "$ARGV at line $. => $_"; } close(STDOUT) or die "can't close STDOUT: $!"; sub tee { my @output = @_; my @handles = (); for my $path (@output) { my $fh; # open will fill this in unless (open ($fh, ">", $path)) { warn "cannot write to $path: $!"; next; } push @handles, $fh; } # reopen STDOUT in parent and return return if my $pid = open(STDOUT, "|-"); die "cannot fork: $!" unless defined $pid; # process STDIN in child while () { for my $fh (@handles) { print $fh $_ or die "tee output failed: $!"; } } for my $fh (@handles) { close($fh) or die "tee closing failed: $!"; } exit; # don't let the child return to main! } -------------- badfunc("arg"); # drat, escaped! $string = forksub(\&badfunc, "arg"); # caught it as string @lines = forksub(\&badfunc, "arg"); # as separate lines sub forksub { my $kidpid = open my $self, "-|"; defined $kidpid or die "cannot fork: $!"; shift->(@_), exit unless $kidpid; local $/ unless wantarray; return <$self>; # closes on scope exit } ################################################################ 16:Interprocess Communication/Pipes/Bidirectional Communication ################################################################ open(PROG_TO_READ_AND_WRITE, "| some program |") # WRONG! -------------- use IPC::Open2; local(*Reader, *Writer); $pid = open2(\*Reader, \*Writer, "bc -l"); $sum = 2; for (1 .. 5) { print Writer "$sum * $sum\n"; chomp($sum = ); } close Writer; close Reader; waitpid($pid, 0); print "sum is $sum\n"; -------------- my($fhread, $fhwrite); $pid = open2($fhread, $fhwrite, "cat -u -n"); -------------- pipe(FROM_PARENT, TO_CHILD) or die "pipe: $!"; pipe(FROM_CHILD, TO_PARENT) or die "pipe: $!"; select((select(TO_CHILD), $| = 1))[0]); # autoflush select((select(TO_PARENT), $| = 1))[0]); # autoflush if ($pid = fork) { close FROM_PARENT; close TO_PARENT; print TO_CHILD "Parent Pid $$ is sending this\n"; chomp($line = ); print "Parent Pid $$ just read this: `$line'\n"; close FROM_CHILD; close TO_CHILD; waitpid($pid,0); } else { die "cannot fork: $!" unless defined $pid; close FROM_CHILD; close TO_CHILD; chomp($line = ); print "Child Pid $$ just read this: `$line'\n"; print TO_PARENT "Child Pid $$ is sending this\n"; close FROM_PARENT; close TO_PARENT; exit; } -------------- use Socket; socketpair(Child, Parent, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; # or letting perl pick filehandles for you my ($kidfh, $dadfh); socketpair($kidfh, $dadfh, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!"; ############################################### 16:Interprocess Communication/Pipes/Named Pipes ############################################### use Fcntl; # for sysopen chdir; # go home $fpath = '.signature'; $ENV{PATH} .= ":/usr/games"; unless (-p $fpath) { # not a pipe if (-e _) { # but a something else die "$0: won't overwrite .signature\n"; } else { require POSIX; POSIX::mkfifo($fpath, 0666) or die "can't mknod $fpath: $!"; warn "$0: created $fpath as a named pipe\n"; } } while (1) { # exit if signature file manually removed die "Pipe file disappeared" unless -p $fpath; # next line blocks until there's a reader sysopen(FIFO, $fpath, O_WRONLY) or die "can't write $fpath: $!"; print FIFO "John Smith (smith\@host.org)\n", `fortune -s`; close FIFO; select(undef, undef, undef, 0.2); # sleep 1/5th second } ########################################## 16:Interprocess Communication/System V IPC ########################################## #!/usr/bin/perl -w use v5.6.0; # or better use strict; use sigtrap qw(die INT TERM HUP QUIT); my $PROGENY = shift(@ARGV) || 3; eval { main() }; # see DESTROY below for why die if $@ && $@ !~ /^Caught a SIG/; print "\nDone.\n"; exit; sub main { my $mem = ShMem->alloc("Original Creation at " . localtime); my(@kids, $child); $SIG{CHLD} = 'IGNORE'; for (my $unborn = $PROGENY; $unborn > 0; $unborn--) { if ($child = fork) { print "$$ begat $child\n"; next; } die "cannot fork: $!" unless defined $child; eval { while (1) { $mem->lock(); $mem->poke("$$ " . localtime) unless $mem->peek =~ /^$$\b/o; $mem->unlock(); } }; die if $@ && $@ !~ /^Caught a SIG/; exit; # child death } while (1) { print "Buffer is ", $mem->get, "\n"; sleep 1; } } -------------- package ShMem; use IPC::SysV qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRWXU); use IPC::Semaphore; sub MAXBUF() { 2000 } sub alloc { # constructor method my $class = shift; my $value = @_ ? shift : ''; my $key = shmget(IPC_PRIVATE, MAXBUF, S_IRWXU) or die "shmget: $!"; my $sem = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRWXU | IPC_CREAT) or die "IPC::Semaphore->new: $!"; $sem->setval(0,1) or die "sem setval: $!"; my $self = bless { OWNER => $$, SHMKEY => $key, SEMA => $sem, } => $class; $self->put($value); return $self; } -------------- sub get { my $self = shift; $self->lock; my $value = $self->peek(@_); $self->unlock; return $value; } sub peek { my $self = shift; shmread($self->{SHMKEY}, my $buff='', 0, MAXBUF) or die "shmread: $!"; substr($buff, index($buff, "\0")) = ''; return $buff; } sub put { my $self = shift; $self->lock; $self->poke(@_); $self->unlock; } sub poke { my($self,$msg) = @_; shmwrite($self->{SHMKEY}, $msg, 0, MAXBUF) or die "shmwrite: $!"; } sub lock { my $self = shift; $self->{SEMA}->op(0,-1,0) or die "semop: $!"; } sub unlock { my $self = shift; $self->{SEMA}->op(0,1,0) or die "semop: $!"; } -------------- sub DESTROY { my $self = shift; return unless $self->{OWNER} == $$; # avoid dup dealloc shmctl($self->{SHMKEY}, IPC_RMID, 0) or warn "shmctl RMID: $!"; $self->{SEMA}->remove() or warn "sema->remove: $!"; } ##################################### 16:Interprocess Communication/Sockets ##################################### #!/usr/bin/perl -w use strict; use sigtrap; use Socket; # or IO::Socket ######################################################### 16:Interprocess Communication/Sockets/Networking Clients ######################################################### use IO::Socket::INET; $socket = IO::Socket::INET->new(PeerAddr => $remote_host, PeerPort => $remote_port, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $remote_host:$remote_port : $!\n"; # send something over the socket, print $socket "Why don't you call me anymore?\n"; # read the remote answer, $answer = <$socket>; # and terminate the connection when we're done # terminate the connection when done close($socket); -------------- $socket = IO::Socket::INET->new("www.yahoo.com:80") or die "Couldn't connect to port 80 of yahoo: $!"; -------------- use Socket; # create a socket socket(Server, PF_INET, SOCK_STREAM, getprotobyname('tcp')); # build the address of the remote machine $internet_addr = inet_aton($remote_host) or die "Couldn't convert $remote_host into an Internet address: $!\n"; $paddr = sockaddr_in($remote_port, $internet_addr); # connect connect(Server, $paddr) or die "Couldn't connect to $remote_host:$remote_port: $!\n"; select((select(Server), $| = 1)[0]); # enable command buffering # send something over the socket print Server "Why don't you call me anymore?\n"; # read the remote answer, $answer = ; # terminate the connection when done close(Server); -------------- # no more writing to server shutdown(Server, 1); # Socket::SHUT_WR constant in v5.6 ######################################################## 16:Interprocess Communication/Sockets/Networking Servers ######################################################## use IO::Socket::INET; $server = IO::Socket::INET->new(LocalPort => $server_port, Type => SOCK_STREAM, Reuse => 1, Listen => 10 ) # or SOMAXCONN or die "Couldn't be a tcp server on port $server_port: $!\n"; while ($client = $server->accept()) { # $client is the new connection } close($server); -------------- use Socket; # make the socket socket(Server, PF_INET, SOCK_STREAM, getprotobyname('tcp')); # so we can restart our server quickly setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1); # build up my socket address $my_addr = sockaddr_in($server_port, INADDR_ANY); bind(Server, $my_addr) or die "Couldn't bind to port $server_port: $!\n"; # establish a queue for incoming connections listen(Server, SOMAXCONN) or die "Couldn't listen on port $server_port: $!\n"; # accept and process connections while (accept(Client, Server)) { # do something with new Client connection } close(Server); -------------- use Socket; $other_end = getpeername(Client) or die "Couldn't identify other end: $!\n"; ($port, $iaddr) = unpack_sockaddr_in($other_end); $actual_ip = inet_ntoa($iaddr); $claimed_hostname = gethostbyaddr($iaddr, AF_INET); -------------- @name_lookup = gethostbyname($claimed_hostname) or die "Could not reverse $claimed_hostname: $!\n"; @resolved_ips = map { inet_ntoa($_) } @name_lookup[ 4 .. $#name_lookup ]; $might_spoof = !grep { $actual_ip eq $_ } @resolved_ips; -------------- REQUEST: while (accept(Client, Server)) { if ($kidpid = fork) { close Client; # parent closes unused handle next REQUEST; } defined($kidpid) or die "cannot fork: $!" ; close Server; # child closes unused handle select(Client); # new default for prints $| = 1; # autoflush # per-connection child code does I/O with Client handle $input = ; print Client "output\n"; # or STDOUT, same thing open(STDIN, "<&Client") or die "can't dup client: $!"; open(STDOUT, ">&Client") or die "can't dup client: $!"; open(STDERR, ">&Client") or die "can't dup client: $!"; # run the calculator, just as an example system("bc -l"); # or whatever you'd like, so long as # it doesn't have shell escapes! print "done\n"; # still to client close Client; exit; # don't let the child back to accept! } ##################################################### 16:Interprocess Communication/Sockets/Message Passing ##################################################### #!/usr/bin/perl # clockdrift - compare other systems' clocks with this one # without arguments, broadcast to anyone listening. # wait one-half second for an answer. use v5.6.0; # or better use warnings; use strict; use Socket; unshift(@ARGV, inet_ntoa(INADDR_BROADCAST)) unless @ARGV; socket(my $msgsock, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!"; # Some borked machines need this. Shouldn't hurt anyone else. setsockopt($msgsock, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!"; my $portno = getservbyname("time", "udp") or die "no udp time port"; for my $target (@ARGV) { print "Sending to $target:$portno\n"; my $destpaddr = sockaddr_in($portno, inet_aton($target)); send($msgsock, "x", 0, $destpaddr) or die "send: $!"; } # daytime service returns 32bit time in seconds since 1900 my $FROM_1900_TO_EPOCH = 2_208_988_800; my $time_fmt = "N"; # and it does so in this binary format my $time_len = length(pack($time_fmt, 1)); # any number's fine my $inmask = ''; # string to store the fileno bits for select vec($inmask, fileno($msgsock), 1) = 1; # wait only half a second for input to show up while (select(my $outmask = $inmask, undef, undef, 0.5)) { defined(my $srcpaddr = recv($msgsock, my $bintime, $time_len, 0)) or die "recv: $!"; my($port, $ipaddr) = sockaddr_in($srcpaddr); my $sendhost = sprintf "%s [%s]", gethostbyaddr($ipaddr, AF_INET) || 'UNKNOWN', inet_ntoa($ipaddr); my $delta = unpack($time_fmt, $bintime) - $FROM_1900_TO_EPOCH - time(); print "Clock on $sendhost is $delta seconds ahead of this one.\n"; } ################################################################### 17:Threads/The Thread Model/The C Module/C creation ################################################################### use Thread; ... $t = Thread->new( \&func, $arg1, $arg2); -------------- my $something; $t = Thread->new( sub { say($something) } ); -------------- use Thread qw(async); ... my $something; $t = async { say($something); }; ###################################################################### 17:Threads/The Thread Model/The C Module/C destruction ###################################################################### $retval = $t->join(); # harvest thread $t -------------- use Thread 'async'; $t1 = async { my @stuff = getpwuid($>); return @stuff; }; $t2 = async { my $motd = `cat /etc/motd`; return $motd; }; @retlist = $t1->join(); $retval = $t2->join(); print "1st kid returned @retlist\n"; print "2nd kid returned $retval\n"; ################################################################################# 17:Threads/The Thread Model/The C Module/Catching exceptions from C ################################################################################# $retval = $t->eval(); # catch join errors if ($@) { warn "thread failed: $@"; } else { print "thread returned $retval\n"; } #################################################################### 17:Threads/The Thread Model/The C Module/Identifying threads #################################################################### $his_tidno = $t1->tid(); -------------- $mytid = Thread->self->tid(); # $$ for threads, as it were. -------------- Thread::equal($t1, $t2) $t1->equal($t2) $t1->tid() == $td->tid() ######################################################################## 17:Threads/The Thread Model/The C Module/Listing current threads ######################################################################## for my $t (Thread->list()) { printf "$t has tid = %d\n", $t->tid(); } ####################################################################### 17:Threads/The Thread Model/The C Module/Yielding the processor ####################################################################### use Thread 'yield'; yield(); -------------- use strict; use Thread 'yield'; yeild; # Compiler wails, then bails. yield; # Ok. ######################################################################### 17:Threads/The Thread Model/Data Access/Synchronizing access with C ######################################################################### lock $var; lock @values; lock %table; -------------- lock @values; # in thread 1 ... lock $values[23]; # in thread 2 -- won't block! -------------- use Thread qw/async yield/; my $var = 0; sub abump { if ($var == 0) { yield; $var++; } } my $t1 = new Thread \&abump; my $t2 = new Thread \&abump; for my $t ($t1, $t2) { $t->join } print "var is $var\n"; -------------- sub abump { lock $var; if ($var == 0) { yield; $var++; } } -------------- sub abump { { lock $var; if ($var == 0) { yield; $var++; } } # lock released here! # other code with unlocked $var } ################################################ 17:Threads/The Thread Model/Data Access/Deadlock ################################################ my $t1 = async { lock $a; yield; lock $b; $a++; $b++ }; my $t2 = async { lock $b; yield; lock $a; $b++; $a++ }; ########################################################### 17:Threads/The Thread Model/Data Access/Locking subroutines ########################################################### lock &func; -------------- use Thread qw/async yield/; my $done = 0; sub frob { my $arg = shift; my $tid = Thread->self->tid; print "thread $tid: frob $arg\n"; yield; unless ($done) { yield; $done++; frob($arg + 10); } } -------------- my @t; for my $i (1..3) { push @t, Thread->new(\&frob, $i); } for (@t) { $_->join } print "done is $done\n"; -------------- for my $i (1..3) { push @t, async { lock &frob; frob($i); }; } for (@t) { $_->join } print "done is $done\n"; ############################################################### 17:Threads/The Thread Model/Data Access/The C attribute ############################################################### sub frob : locked { # as before } -------------- sub frob ($) : locked { # as before } ####################################################### 17:Threads/The Thread Model/Data Access/Locking methods ####################################################### sub frob : locked method { # as before } ########################################################### 17:Threads/The Thread Model/Data Access/Condition variables ########################################################### use Thread qw(async cond_wait cond_signal); my $wait_var = 0; async { lock $wait_var; $wait_var = 1; cond_wait $wait_var until $wait_var == 2; cond_signal($wait_var); $wait_var = 1; cond_wait $wait_var until $wait_var == 2; $wait_var = 1; cond_signal($wait_var); }; async { lock $wait_var; cond_wait $wait_var until $wait_var == 1; $wait_var = 2; cond_signal($wait_var); cond_wait $wait_var until $wait_var == 1; $wait_var = 2; cond_signal($wait_var); cond_wait $wait_var until $wait_var == 1; }; ########################################################### 17:Threads/The Thread Model/Thread Modules/C ########################################################### use Thread qw/async/; use Thread::Queue; my $Q = Thread::Queue->new(); async { while (defined($datum = $Q->dequeue)) { print "Pulled $datum from queue\n"; } }; $Q->enqueue(12); $Q->enqueue("A", "B", "C"); $Q->enqueue($thr); sleep 3; $Q->enqueue(\%ENV); $Q->enqueue(undef); ########################################################### 17:Threads/The Thread Model/Thread Modules/Using semaphores ########################################################### use Thread::Semaphore; $mutex = Thread::Semaphore->new(MAX); -------------- $mutex->down(); -------------- $mutex->up(); ############################################## 18:Internals and Externals/Compiling Your Code ############################################## if (2 * sin(1)/cos(1) < 3 && somefn()) { whatever() } -------------- if (somefn() && 2 * sin(1)/cos(1) < 3)) { whatever() } ################################################################# 18:Internals and Externals/Code Generators/The Bytecode Generator ################################################################# % perlcc -b -o pbyscript srcscript -------------- #!/usr/bin/perl use ByteLoader 0.03; ^C^@^E^A^C^@^@^@^A^F^@^C^@^@^@^B^F^@^C^@^@^@^C^F^@^C^@^@^@ B^@^@^@^H9^A8M-^?M-^?M-^?M-^?7M-^?M-^?M-^?M-^?6^@^@^@^A6^@ ^G^D^D^@^@^@^KR^@^@^@^HS^@^@^@^HV^@M-2W<^FU^@^@^@^@X^Y@Z^@ ... ################################################# 18:Internals and Externals/Code Development Tools ################################################# % perl -MO=Lint,all myprog -------------- % perl -MO=Xref myprog > myprof.pxref -------------- % perl -MO=Deparse -ne 'for (1 .. 10) { print if -t }' LINE: while (defined($_ = )) { foreach $_ (1 .. 10) { print $_ if -t STDIN; } } -------------- % perl -MO=Deparse,-p -e 'print $a ** 3 + sqrt(2) / 10 ** -2 ** $c' print((($a ** 3) + (1.4142135623731 / (10 ** (-(2 ** $c)))))); -------------- % perl -MO=Deparse,-q -e '"A $name and some @ARGV\n"' 'A ' . $name . ' and some ' . join($", @ARGV) . "\n"; -------------- % perl -MO=Deparse -e 'for ($i=0;$i<10;$i++) { $x++ }' $i = 0; while ($i < 10) { ++$x; } continue { ++$i } ################################################################## 18:Internals and Externals/Avant-garde Compiler, Retro Interpreter ################################################################## #!/usr/bin/perl -l print "start main running here"; die "main now dying here\n"; die "XXX: not reached\n"; END { print "1st END: done running" } CHECK { print "1st CHECK: done compiling" } INIT { print "1st INIT: started running" } END { print "2nd END: done running" } BEGIN { print "1st BEGIN: still compiling" } INIT { print "2nd INIT: started running" } BEGIN { print "2nd BEGIN: still compiling" } CHECK { print "2nd CHECK: done compiling" } END { print "3rd END: done running" } -------------- BEGIN { print "main begun" } END { print "main ended" } use Module; -------------- BEGIN { print "module begun" } END { print "module ended" } ################################################ 19:The Command Line Interface/Command Processing ################################################ % perl -e "print 'Hello, World.'" Hello, World. -------------- % echo "print qq(Hello, @ARGV.)" | perl - World Hello, World. -------------- #!/bin/sh -- # -*- perl -*- -p eval 'exec perl -S $0 ${1+"$@"}' if 0; -------------- #!/usr/bin/env perl -------------- #!/bin/sh echo "I am a shell script" ###################################################################################### 19:The Command Line Interface/Command Processing/C<#!> and quoting on non-Unix systems ###################################################################################### extproc perl -S -your_switches -------------- % perl -mysw 'f$env("procedure")' 'p1' 'p2' 'p3' 'p4' 'p5' 'p6' 'p7' 'p8' ! $ exit++ + ++$status != 0 and $exit = $status = undef; -------------- % perl -e 'print "Hello world\n"' -------------- $ perl -e "print ""Hello world\n""" -------------- $ perl -e "print qq(Hello world\n)" -------------- A:> perl -e "print \"Hello world\n\"" -------------- A:> perl -e "print qq(Hello world\n)" -------------- perl -e "print "Hello world\n"" ################################################################# 19:The Command Line Interface/Command Processing/Location of Perl ################################################################# #!/usr/local/bin/perl5.6.0 -------------- use v5.6.0; ######################################################### 19:The Command Line Interface/Command Processing/Switches ######################################################### #!/usr/bin/perl -spi.bak # same as -s -p -i.bak -------------- % find . -name '*.bak' -print0 | perl -n0e unlink -------------- % perl -ane 'print pop(@F), "\n";' -------------- LINE: while (<>) { @F = split(' '); print pop(@F), "\n"; } -------------- % awk -F: '$7 && $7 !~ /^\/bin/' /etc/passwd % perl -F: -lane 'print if $F[6] && $F[6] !~ m(^/bin)' /etc/passwd -------------- BEGIN { $^C = 0; exit; } -------------- # Bourne shell syntax $ PERLDB_OPTS="NonStop=1 AutoTrace=1 frame=2" perl -dS program # csh syntax % (setenv PERLDB_OPTS "NonStop=1 AutoTrace=1 frame=2"; perl -dS program) -------------- $ perl -e 'print "Howdy, "; print "@ARGV!\n";' world Howdy, world! -------------- % perl -e 'print "Howdy, ";' \ -e 'print "@ARGV!\n";' world Howdy, world! -------------- ($backup = $extension) =~ s/\*/$file_name/g; -------------- % perl -pi'orig_*' -e 's/foo/bar/' xyx # backup to 'orig_xyx' -------------- % perl -pi'old/*.orig' -e 's/foo/bar/' xyx # backup to 'old/xyx.orig' -------------- % perl -pi -e 's/foo/bar/' xyx # overwrite current file % perl -pi'*' -e 's/foo/bar/' xyx # overwrite current file % perl -pi'.orig' -e 's/foo/bar/' xyx # backup to 'xyx.orig' % perl -pi'*.orig' -e 's/foo/bar/' xyx # backup to 'xyx.orig' -------------- % perl -p -i.orig -e "s/foo/bar/;" -------------- #!/usr/bin/perl -pi.orig s/foo/bar/; -------------- #!/usr/bin/perl $extension = '.orig'; LINE: while (<>) { if ($ARGV ne $oldargv) { if ($extension !~ /\*/) { $backup = $ARGV . $extension; } else { ($backup = $extension) =~ s/\*/$ARGV/g; } unless (rename($ARGV, $backup)) { warn "cannot rename $ARGV to $backup: $!\n"; close ARGV; next; } open(ARGVOUT, ">$ARGV"); select(ARGVOUT); $oldargv = $ARGV; } s/foo/bar/; } continue { print; # this prints to original filename } select(STDOUT); -------------- % perl -pi~ -e 's/foo/bar/' file1 file2 file3... -------------- % perl -lpe 'substr($_, 80) = ""' -------------- % gnufind / -print0 | perl -ln0e 'print "found $_" if -p' -------------- use module split(/,/, q{foo,bar}) -------------- LINE: while (<>) { ... # your script goes here } -------------- find . -mtime +7 -print | perl -nle unlink -------------- LINE: while (<>) { ... # your script goes here } continue { print or die "-p destination: $!\n"; } -------------- #!/usr/bin/perl -s if ($foo) { print "true\n" } -------------- #!/usr/bin/perl -s if ($foo eq 'bar') { print "true\n" } -------------- #!/usr/bin/perl eval "exec /usr/bin/perl -S $0 $*" if $running_under_some_shell; -------------- eval '(exit $?0)' && eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' & eval 'exec /usr/bin/perl -S $0 $argv:q' if 0; -------------- % perl -V:man.dir man1dir='/usr/local/man/man1' man3dir='/usr/local/man/man3' % perl -V:'.*threads' d_oldpthreads='undef' use5005threads='define' useithreads='undef' usethreads='define' -------------- % perl -MConfig -le 'print $Config{man1dir}' /usr/local/man/man1 ################################################### 19:The Command Line Interface/Environment Variables ################################################### $ PATH='/bin:/usr/bin' perl myproggie -------------- % (setenv PATH "/bin:/usr/bin"; perl myproggie) -------------- % setenv PATH '/bin:/usr/bin' -------------- $ PATH='/bin:/usr/bin'; export PATH -------------- BEGIN { require 'perl5db.pl' } -------------- $ENV{PATH} = '/bin:/usr/bin'; # or whatever you need $ENV{SHELL} = '/bin/sh' if exists $ENV{SHELL}; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; #################### 20:The Perl Debugger #################### % perl -de 42 -------------- % perl -d /path/to/program ####################################### 20:The Perl Debugger/Using the Debugger ####################################### DB<8> -------------- DB<<17>> -------------- DB<1> B cont: B cont: B<}> ok ok ok -------------- % B Loading DB routines from perl5db.pl version 1.07 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(camel_flea:2): pests('bactrian', 4); DB<1> -------------- DB<1> B DB<2> B -------------- main::infested(camel_flea:8): my $bugs = int rand(3); -------------- DB<2> B 5 } 6 7 sub infested { 8==>b my $bugs = int rand(3); 9: our $Master; 10: contaminate($Master); 11: warn "needs wash" 12 if $Master && $Master->isa("Human"); 13 14: print "got $bugs\n"; DB<2> -------------- DB<2> B $ = main::infested called from file `Ambulation.pm' line 4 @ = Ambulation::legs(1, 2, 3, 4) called from file `camel_flea' line 5 . = main::pests('bactrian', 4) called from file `camel_flea' line 2 -------------- $DB::single = 1; -------------- DB<7> B Will stop on load of `c:/perl/lib/Carp.pm'. ###################################### 20:The Perl Debugger/Debugger Commands ###################################### DB<1> B<|h> ################################################## 20:The Perl Debugger/Debugger Commands/Breakpoints ################################################## b 237 $x > 30 b 237 ++$count237 < 11 b 33 /pattern/i ############################################## 20:The Perl Debugger/Debugger Commands/Display ############################################## V Pet::Camel SPOT FIDO #################################################################### 20:The Perl Debugger/Debugger Commands/Actions and Command Execution #################################################################### a 53 print "DB FOUND $foo\n" -------------- DB<1> |V main -------------- DB<1> !!who | more -------------- DB<1> sub saywho { print "Users: ", `who` } DB<2> ||sawwho() ####################################################################### 20:The Perl Debugger/Debugger Customization/Customizing with Init Files ####################################################################### $alias{len} = 's/^len(.*)/p length($1)/'; $alias{stop} = 's/^stop (at|in)/b/'; $alias{ps} = 's/^ps\b/p scalar /'; $alias{quit} = 's/^quit(\s*)/exit/'; $alias{help} = 's/^help\s*$/|h/'; -------------- parse_options("NonStop=1 LineInfo=db.out AutoTrace=1 frame=2"); -------------- BEGIN { require "myperl5db.pl" } ######################################### 20:The Perl Debugger/Unattended Execution ######################################### parse_options("NonStop=1 LineInfo=tperl.out AutoTrace"); -------------- $ PERLDB_OPTS="NonStop frame=1 AutoTrace LineInfo=tperl.out" perl -d myprog ################################################################# 20:The Perl Debugger/Debugger Internals/Writing Your Own Debugger ################################################################# sub DB::DB {} -------------- $ PERL5DB="sub DB::DB {}" perl -d your-program -------------- sub DB::DB {print ++$i; scalar } -------------- { package DB; sub DB {} sub sub {print ++$i, " $sub\n"; &$sub} } ###################################### 20:The Perl Debugger/The Perl Profiler ###################################### perl -d:DProf mycode.pl -------------- outer(); sub outer { for (my $i=0; $i < 100; $i++) { inner() } } sub inner { my $total = 0; for (my $i=0; $i < 1000; $i++) { $total += $i } } inner(); ################################## 21:The Guts of Perl/How Perl Works ################################## print "Hello, world!\n"; ################################################################### 21:The Guts of Perl/Extending Perl (Using C from Perl)/XS and XSUBs ################################################################### double sin(x) double x ########################################################################## 21:The Guts of Perl/Extending Perl (Using C from Perl)/Creating Extensions ########################################################################## h2xs -A -n Mytest -------------- package Mytest; use strict; use warnings; require Exporter; require DynaLoader; our @ISA = qw(Exporter DynaLoader); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. our @EXPORT = qw( ); our $VERSION = '0.01'; bootstrap Mytest $VERSION; # Preloaded methods go here. # Autoload methods go after __END__, and are processed by the autosplit program. 1; __END__ # Below is the stub of documentation for your module. You better edit it! -------------- #include "EXTERN.h" #include "perl.h" #include "XSUB.h" MODULE = Mytest PACKAGE = Mytest -------------- void hello() CODE: printf("Hello, world!\n"); -------------- % perl Makefile.PL Checking if your kit is complete... Looks good Writing Makefile for Mytest % -------------- % make umask 0 && cp Mytest.pm ./blib/Mytest.pm perl xsubpp -typemap typemap Mytest.xs >Mytest.tc && mv Mytest.tc Mytest.c cc -c Mytest.c Running Mkbootstrap for Mytest () chmod 644 Mytest.bs LD_RUN_PATH="" ld -o ./blib/PA-RISC1.1/auto/Mytest/Mytest.sl -b Mytest.o chmod 755 ./blib/PA-RISC1.1/auto/Mytest/Mytest.sl cp Mytest.bs ./blib/PA-RISC1.1/auto/Mytest/Mytest.bs chmod 644 ./blib/PA-RISC1.1/auto/Mytest/Mytest.bs Manifying ./blib/man3/Mytest.3 % -------------- perl -V:make -------------- use ExtUtils::testlib; # adds blib/* directories to @INC use Mytest; Mytest::hello(); -------------- % perl hello Hello, world! % -------------- make install ############################################################################ 21:The Guts of Perl/Extending Perl (Using C from Perl)/XSUB Input and Output ############################################################################ int is_even(x) int x CODE: RETVAL = (x % 2 == 0); OUTPUT: RETVAL -------------- print Mytest::is_even(0) == 1 ? "ok 2" : "not ok 2", "\n"; print Mytest::is_even(1) == 0 ? "ok 3" : "not ok 3", "\n"; print Mytest::is_even(2) == 1 ? "ok 4" : "not ok 4", "\n"; ################################################################################################# 21:The Guts of Perl/Extending Perl (Using C from Perl)/Using Functions from an External C Library ################################################################################################# void round(arg) double arg CODE: if (arg > 0.0) { arg = floor(arg + 0.5); } else if (arg < 0.0) { arg = ceil(arg - 0.5); } else { arg = 0.0; } OUTPUT: arg -------------- 'LIBS' => ['-lm'], # Link in the 'm' math library -------------- $i = -1.5; Mytest::round($i); print $i == -2.0 ? "ok 5" : "not ok 5", "\n"; $i = -1.1; Mytest::round($i); print $i == -1.0 ? "ok 6" : "not ok 6", "\n"; $i = 0.0; Mytest::round($i); print $i == 0.0 ? "ok 7" : "not ok 7", "\n"; $i = 0.5; Mytest::round($i); print $i == 1.0 ? "ok 8" : "not ok 8", "\n"; $i = 1.2; Mytest::round($i); print $i == 1.0 ? "ok 9" : "not ok 9", "\n"; ################################################################################## 21:The Guts of Perl/Embedding Perl (Using Perl from C)/Compiling Embedded Programs ################################################################################## perl -MConfig -e "print $Config{archlib}" -------------- perl -MConfig -e "print $Config{cc}" -------------- % cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts` ################################################################################################## 21:The Guts of Perl/Embedding Perl (Using Perl from C)/Adding a Perl Interpreter to Your C Program ################################################################################################## #include /* from the Perl distribution */ #include /* from the Perl distribution */ static PerlInterpreter *my_perl; /*** The Perl interpreter ***/ int main(int argc, char **argv, char **env) { my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, (char **)NULL); perl_run(my_perl); perl_destruct(my_perl); perl_free(my_perl); } -------------- % interp -e "printf('%x', 3735928559)" deadbeef ####################################################################################### 21:The Guts of Perl/Embedding Perl (Using Perl from C)/Calling a Perl Subroutine From C ####################################################################################### print "I shan't be printed."; sub showtime { print time; } -------------- #include #include static PerlInterpreter *my_perl; int main(int argc, char **argv, char **env) { char *args[] = { NULL }; my_perl = perl_alloc(); perl_construct(my_perl); perl_parse(my_perl, NULL, argc, argv, NULL); /*** skipping perl_run() ***/ call_argv("showtime", G_DISCARD | G_NOARGS, args); perl_destruct(my_perl); perl_free(my_perl); } -------------- % cc -o showtime showtime.c `perl -MExtUtils::Embed -e ccopts -e ldopts` % showtime showtime.pl 963852741 ######################################################################################### 21:The Guts of Perl/Embedding Perl (Using Perl from C)/Evaluating a Perl Statement From C ######################################################################################### #include #include static PerlInterpreter *my_perl; main (int argc, char **argv, char **env) { STRLEN n_a; char *embedding[] = { "", "-e", "0" }; my_perl = perl_alloc(); perl_construct( my_perl ); perl_parse(my_perl, NULL, 3, embedding, NULL); perl_run(my_perl); /** Treat $a as an integer **/ eval_pv("$a = 3; $a **= 2", TRUE); printf("a = %d\n", SvIV(get_sv("a", FALSE))); /** Treat $a as a float **/ eval_pv("$a = 3.14; $a **= 2", TRUE); printf("a = %f\n", SvNV(get_sv("a", FALSE))); /** Treat $a as a string **/ eval_pv("$a = 'relreP kcaH rehtonA tsuJ'; $a = reverse($a);", TRUE); printf("a = %s\n", SvPV(get_sv("a", FALSE), n_a)); perl_destruct(my_perl); perl_free(my_perl); } -------------- a = 9 a = 9.859600 a = Just Another Hack Perler -------------- SV *val = eval_pv("reverse 'relreP kcaH rehtonA tsuJ'", TRUE); printf("%s\n", SvPV(val,n_a)); ########################################################################################## 21:The Guts of Perl/Embedding Perl (Using Perl from C)/Fiddling With the Perl Stack From C ########################################################################################## sub expo { my ($a, $b) = @_; return $a ** $b; } -------------- #include #include static PerlInterpreter *my_perl; /* "Real programmers can write assembly code in any language." */ static void PerlPower(int a, int b) { dSP; /* initialize stack pointer */ ENTER; /* everything created after here */ SAVETMPS; /* ...is a temporary variable. */ PUSHMARK(SP); /* remember the stack pointer */ XPUSHs(sv_2mortal(newSViv(a))); /* push the base onto the stack */ XPUSHs(sv_2mortal(newSViv(b))); /* push the exponent onto stack */ PUTBACK; /* make local stack pointer global */ call_pv("expo", G_SCALAR); /* call the function */ SPAGAIN; /* refresh stack pointer */ /* pop the return value from stack */ printf ("%d to the %dth power is %d.\n", a, b, POPi); PUTBACK; FREETMPS; /* free that return value */ LEAVE; /*...and the XPUSHed "mortal" args */ } int main (int argc, char **argv, char **env) { char *my_argv[] = { "", "power.pl" }; my_perl = perl_alloc(); perl_construct( my_perl ); perl_parse(my_perl, NULL, 2, my_argv, (char **)NULL); perl_run(my_perl); PerlPower(3, 4); /*** Compute 3 ** 4 ***/ perl_destruct(my_perl); perl_free(my_perl); } -------------- % cc -o power power.c `perl -MExtUtils::Embed -e ccopts -e ldopts` % power 3 to the 4th power is 81. ########################## 22:CPAN/Using CPAN Modules ########################## % perl -MCPAN -e "shell" -------------- install Some::Module -------------- % perl -MCPAN -e "install 'Some::Module'" ################################################ 22:CPAN/Using CPAN Modules/Building CPAN Modules ################################################ % perl Makefile.PL % make % make test ######################################################################## 22:CPAN/Using CPAN Modules/Installing CPAN Modules into the Perl Library ######################################################################## % perl -V -------------- % make install -------------- % perl Makefile.PL LIB=/my/dir/perllib \ INSTALLMAN1DIR=/my/dir/man/man1 \ INSTALLMAN3DIR=/my/dir/man/man3 \ INSTALLBIN=/my/dir/bin \ INSTALLSCRIPT=/my/dir/scripts -------------- use lib "/my/dir/perllib"; ############################# 22:CPAN/Creating CPAN Modules ############################# h2xs -X -n Foo::Bar -------------- use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( NAME => 'Mytest', VERSION_FROM => 'Mytest.pm', # finds $VERSION LIBS => [''], # e.g., '-lm' DEFINE => '', # e.g., '-DHAVE_SOMETHING' INC => '', # e.g., '-I/usr/include/other' ); -------------- eval { require 5.6.0 } or die <<'EOD'; ############ ### This module requires lvaluable subroutines, which are not available ### in versions of Perl earlier than 5.6. Please upgrade! ############ EOD ################################## 23:Security/Handling Insecure Data ################################## $arg = shift(@ARGV); # $arg tainted (due to @ARGV). $hid = "$arg, 'bar'"; # $hid also tainted (due to $arg). $line = <>; # Tainted (reading from external file). $path = $ENV{PATH}; # Tainted due to %ENV, but see below. $mine = 'abc'; # Not tainted. system "echo $mine"; # Insecure until PATH set. system "echo $arg"; # Insecure: uses sh with tainted $arg. system "echo", $arg; # OK once PATH set (doesn't use sh). system "echo $hid"; # Insecure two ways: taint, PATH. $oldpath = $ENV{PATH}; # $oldpath is tainted (due to $ENV). $ENV{PATH} = '/bin:/usr/bin'; # (Make ok to execute other programs.) $newpath = $ENV{PATH}; # $newpath is NOT tainted. delete @ENV{qw{IFS CDPATH ENV BASH_ENV}}; # Make %ENV safer. system "echo $mine"; # OK, is secure once path is reset. system "echo $hid"; # Insecure via tainted $hid. open(OOF, "< $arg"); # OK (read-only opens not checked). open(OOF, "> $arg"); # Insecure (trying to write to tainted arg). open(OOF, "echo $arg|") # Insecure due to tainted $arg, but... or die "can't pipe from echo: $!"; open(OOF,"-|") # Considered OK: see below for taint or exec 'echo', $arg # exemption on exec'ing a list. or die "can't exec echo: $!"; open(OOF,"-|", 'echo', $arg # Same as previous, likewise OKish. or die "can't pipe from echo: $!"; $shout = `echo $arg`; # Insecure via tainted $arg. $shout = `echo abc`; # $shout is tainted due to backticks. $shout2 = `echo $shout`; # Insecure via tainted $shout. unlink $mine, $arg; # Insecure via tainted $arg. umask $arg; # Insecure via tainted $arg. exec "echo $arg"; # Insecure via tainted $arg passed to shell. exec "echo", $arg; # Considered OK! (But see below.) exec "sh", '-c', $arg; # Considered OK, but isn't really! -------------- system @args; # Won't call the shell unless @args == 1. system { $args[0] } @args; # Safe even with one-argument list. ######################################################################## 23:Security/Handling Insecure Data/Detecting and laundering tainted data ######################################################################## sub is_tainted { my $arg = shift; my $nada = substr($arg, 0, 0); # zero-length local $@; # preserve caller's version eval { eval "# $nada" }; return length($@) != 0; } -------------- if ($string =~ /^([-\@\w.]+)$/) { $string = $1; # $string now untainted. } else { die "Bad data in $string"; # Log this somewhere. } -------------- ($dir, $file) = $fullpath =~ m!(.*/)(.*)!s; -------------- { use re 'taint'; ($dir, $file) = $fullpath =~ m!(.*/)(.*)!s; } -------------- use re 'taint'; # remainder of file now leave $1 etc tainted { no re 'taint'; # this block now untaints re matches if ($num =~ /^(\d+)$/) { $num = $1; } } -------------- use IO::Handle; IO::Handle::untaint(*SOME_FH); # Either procedurally SOME_FH->untaint(); # or using the OO style. -------------- use File::stat; use Symbol 'qualify_to_ref'; sub handle_looks_safe(*) { my $fh = qualify_to_ref(shift, caller); my $info = stat($fh); return unless $info; # owner neither superuser nor "me", whose # real uid is in the $< variable if ($info->uid != 0 && $info->uid != $<) { return 0; } # check whether group or other can write file. # use 066 to detect for readability also if ($info->mode & 022) { return 0; } return 1; } use IO::Handle; SOME_FH->untaint() if handle_looks_safe(*SOME_FH); -------------- $new_guestbook_entry =~ tr[_a-zA-Z0-9 ,./!?()@+*-][]dc; ############################################################### 23:Security/Handling Insecure Data/Cleaning up your environment ############################################################### delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer -------------- # Magic open--could be anything open(FH, $file) or die "can't magic open $file: $!"; # Guaranteed to be a read-only file open and not a pipe # or fork, but still groks file descriptors and "-", # and ignores whitespace at either end of name. open(FH, "< $file") or die "can't open $file: $!"; # WYSIWYG open: disables all convenience features. open(FH, "<", $file) or die "can't open $file: $!"; # Same properties as WYSIWYG 3-arg version. require Fcntl; sysopen(FH, $file, O_RDONLY) or die "can't sysopen $file: $!"; ######################################################################################## 23:Security/Handling Insecure Data/Accessing commands and files under reduced privileges ######################################################################################## use English; # to use $UID, etc die "Can't fork open: $!" unless defined($pid = open(FROMKID, "-|")); if ($pid) { # parent while () { # do something } close FROMKID; } else { $EUID = $UID; # setuid(getuid()) $EGID = $GID; # setgid(getgid()), and initgroups(2) on getgroups(2) chdir("/") or die "can't chdir to /: $!"; umask(077); $ENV{PATH} = "/bin:/usr/bin"; exec 'myprog', 'arg1', 'arg2'; die "can't exec myprog: $!"; } -------------- open(FROMKID, "-|") or exec("myprog", "arg1", "arg2") or die "can't run myprog: $!"; -------------- open(FROMKID, "-|", "myprog", "arg1", "arg2"); -------------- use English; defined ($pid = open(SAFE_WRITER, "|-")) or die "Can't fork: $!"; if ($pid) { # you're the parent. write data to SAFE_WRITER child print SAFE_WRITER "@output_data\n"; close SAFE_WRITER or die $! ? "Syserr closing SAFE_WRITER writer: $!" : "Wait status $? from SAFE_WRITER writer"; } else { # you're the child, so drop extra privileges ($EUID, $EGID) = ($UID, $GID); # open the file under original user's rights open(FH, "> /some/file/path") or die "can't open /some/file/path for writing: $!"; # copy from parent (now stdin) into the file while () { print FH $_; } close(FH) or die "close failed: $!"; exit; # Don't forget to make the SAFE_WRITER disappear. } #################################### 23:Security/Handling Timing Glitches #################################### $var++ if $var == 0; -------------- { lock($var); $var++ if $var == 0; } ############################################################## 23:Security/Handling Timing Glitches/Unix kernel security bugs ############################################################## #define REAL_FILE "/path/to/script" main(ac, av) char **av; { execv(REAL_FILE, av); } ############################################################# 23:Security/Handling Timing Glitches/Handling race conditions ############################################################# if (-e $file) { open(FH, "< $file") or die "can't open $file for reading: $!"; } else { open(FH, "> $file") or die "can't open $file for writing: $!"; } -------------- use Fcntl qw/O_WRONLY O_CREAT O_EXCL/; open(FH, "<", $file) or sysopen(FH, $file, O_WRONLY | O_CREAT | O_EXCL) or die "can't create new file $file: $!"; #################################################### 23:Security/Handling Timing Glitches/Temporary files #################################################### open(TMP, ">/tmp/foo.$$") or die "can't open /tmp/foo.$$: $!"; -------------- # Keep trying names until we get one that's brand new. use POSIX; do { $name = tmpnam(); } until sysopen(TMP, $name, O_RDWR | O_CREAT | O_EXCL, 0600); # Now do I/O using TMP handle. -------------- # Or else let the module do that for us. use IO::File; my $fh = IO::File::new_tmpfile(); # this is POSIX's tmpfile(3) # Now do I/O using $fh handle. -------------- $virtname = "/dev/fd/" . fileno(TMP); -------------- $virtname = "=&" . fileno(TMP); ################################################################################# 23:Security/Handling Insecure Code/Safe compartments/Restricting namespace access ################################################################################# use Safe; my $sandbox = Safe->new("Dungeon"); $Dungeon::foo = 1; # Direct access is discouraged, though. -------------- use Safe; $Dungeon::foo = 1; # Still direct access, still discouraged. my $sandbox = Safe->new("Dungeon"); -------------- use Safe; my $sandbox = Safe->new(); $sandbox->reval('$foo = 1'); -------------- $sandbox->reval('$foo++; print "foo is now $main::foo\n"'); if ($@) { die "Couldn't compile code in box: $@"; } -------------- $sandbox->reval(q{ our $foo; sub say_foo { print "foo is now $main::foo\n"; } }, 1); die if $@; # check compilation -------------- $sandbox->reval('say_foo()'); # Best way. die if $@; $sandbox->varglob('say_foo')->(); # Call through anonymous glob. Dungeon::say_foo(); # Direct call, strongly discouraged. ################################################################## 23:Security/Handling Insecure Code/Safe compartments/Safe examples ################################################################## #!/usr/bin/perl -lTw use strict; use CGI::Carp 'fatalsToBrowser'; use CGI qw/:standard escapeHTML/; use Safe; print header(-type => "text/html;charset=UTF-8"), start_html("Perl Expression Results"); my $expr = param("EXPR") =~ /^([^;]+)/ ? $1 # return the now-taintless portion : croak("no valid EXPR field in form"); my $answer = Safe->new->reval($expr); die if $@; print p("Result of", tt(escapeHTML($expr)), "is", tt(escapeHTML($answer))); -------------- #!/usr/bin/perl -w # safecalc - demo program for playing with Safe use strict; use Safe; my $sandbox = Safe->new(); while (1) { print "Input: "; my $expr = ; exit unless defined $expr; chomp($expr); print "$expr produces "; local $SIG{__WARN__} = sub { die @_ }; my $result = $sandbox->reval($expr, 1); if ($@ =~ s/at \(eval \d+\).*//) { printf "[%s]: %s", $@ =~ /trapped by operation mask/ ? "Security Violation" : "Exception", $@; } else { print "[Normal Result] $result\n"; } } ############################################################ 23:Security/Handling Insecure Code/Code Masquerading as Data ############################################################ $new = $old; # No quoting needed. print "$new items\n"; # $new can't hurt you. $phrase = "$new items\n"; # Nor here, neither. print $phrase; # Still perfectly ok. -------------- $phrase = "You lost @{[ 1 + int rand(6) ]} hit points\n"; -------------- $count = '1 + int rand(6)'; # Some random code. $saying = "$count hit points"; # Merely a literal. $saying = "@{[$count]} hit points"; # Also a literal. -------------- $code = '1 + int rand(6)'; $die_roll = eval $code; die if $@; -------------- $cnt = $n = 0; while ($data =~ /( \d+ (?{ $n++ }) | \w+ )/gx) { $cnt++; } print "Got $cnt words, $n of which were digits.\n"; -------------- unless (defined($match = )) { # do something appropriate on premature end-of-file } chomp($match); if (length($match)) { $last_match = $match } else { $match = $last_match } if (not eval { "" =~ /$match/; 1 }) { # Use the empty string to avoid undef warnings. # Also catches (?{...}) interpolation exceptions. # (Now do whatever you want for a bad pattern.) } else { # We know pattern is at least safe to compile. if ($data =~ /$match/) { .... } } ############################################################### 24:Common Practices/Common Goofs for Novices/Universal Blunders ############################################################### print STDOUT, "goodbye", $adj, "world!\n"; # WRONG -------------- print STDOUT "goodbye", $adj, "world!\n"; # ok -------------- print $filehandle "goodbye", $adj, "world!\n"; -------------- print $notafilehandle, "goodbye", $adj, "world!\n"; -------------- print <<'FINIS'; A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines. --Ralph Waldo Emerson FINIS -------------- my ($one, $two) = /(\w+) (\w+)/; -------------- print "the answer is @foo[1]\n"; -------------- @foo[1] = ; -------------- my $x, $y = (4, 8); # WRONG my ($x, $y) = (4, 8); # ok ###################################################################### 24:Common Practices/Common Goofs for Novices/Frequently Ignored Advice ###################################################################### ($x) = (4, 5, 6); # List context; $x is set to 4 $x = (4, 5, 6); # Scalar context; $x is set to 6 @a = (4, 5, 6); $x = @a; # Scalar context; $x is set to 3 -------------- print "hi"; # WRONG, omit angles -------------- while () { } while ($_ = ) { }.. ; # Data read and discarded! -------------- $x = /foo/; # Searches $_, puts result in $x $x =~ /foo/; # Searches $x, discards result #################################################### 24:Common Practices/Common Goofs for Novices/C Traps #################################################### if (expression) { block; } else if (another_expression) { # WRONG another_block; } -------------- if (expression) { block; } elsif (another_expression) { another_block; } ######################################################## 24:Common Practices/Common Goofs for Novices/Shell Traps ######################################################## camel='dromedary'; # WRONG -------------- $camel='dromedary'; # ok -------------- foreach hump (one two) stuff_it $hump end -------------- foreach $hump ("one", "two") { stuff_it($hump); } -------------- chomp($thishost = `hostname`); ################################################################ 24:Common Practices/Common Goofs for Novices/Previous Perl Traps ################################################################ sub SeeYa { die "Hasta la vista, baby!" } $SIG{'QUIT'} = SeeYa; -------------- print "$a::$b::$c\n"; -------------- print "$var::abc::xyz\n"; -------------- shift @list + 20; # Now parses like shift(@list + 20), illegal! $n = keys %map + 20; # Now parses like keys(%map + 20), illegal! -------------- sleep $dormancy + 20; -------------- /foo/ ? ($a += 2) : ($a -= 2); -------------- /foo/ ? $a += 2 : $a -= 2; -------------- (/foo/ ? $a += 2 : $a) -= 2; -------------- $a += /foo/ ? 1 : 2; -------------- % perl4 -e '@a = (1,2,3); for (grep(/./, @a)) { $_++ }; print "@a\n"' 1 2 3 % perl5 -e '@a = (1,2,3); for (grep(/./, @a)) { $_++ }; print "@a\n"' 2 3 4 -------------- foreach $var (grep /x/, @list) { ... } -------------- foreach $var (my @tmp = grep /x/, @list) { ... } ############################################## 24:Common Practices/Efficiency/Time Efficiency ############################################## my %keywords; for (@keywords) { $keywords{$_}++; } -------------- no strict 'refs'; $name = "variable"; $$name = 7; # Sets $variable to 7 -------------- "foundstring" =~ /$currentpattern/; # Dummy match (must succeed). while (<>) { print if //; } -------------- print if /one-hump/ || /two/; -------------- print if /one-hump|two/; -------------- while (<>) { next if /^#/; next if /^$/; chop; @piggies = split(/,/); ... } -------------- while ($buffer) { process(substr($buffer, 0, 10, "")); } -------------- $foo = substr($foo,0,3) . $bar . substr($foo,6); -------------- substr($foo, 3, 3) = $bar; -------------- if ($a) { $foo = $a; } elsif ($b) { $foo = $b; } elsif ($c) { $foo = $c; } -------------- $pi ||= 3; -------------- print $fullname{$name} . " has a new home directory " . $home{$name} . "\n"; -------------- print $fullname{$name}, " has a new home directory ", $home{$name}, "\n"; -------------- sub numtoname { local($_) = @_; unless (defined $numtoname{$_}) { local(@a) = gethostbyaddr(pack('C4', split(/\./)),2); $numtoname{$_} = @a > 0 ? $a[0] : $_; } $numtoname{$_}; } -------------- chmod +t /usr/bin/perl ############################################## 24:Common Practices/Efficiency/User Efficiency ############################################## open(FILE, $file) or die "$0: Can't open $file for reading: $!\n"; ########################################## 24:Common Practices/Programming with Style ########################################## while ($condition) { # for short ones, align with keywords # do something } # if the condition wraps, line up the braces with each other while ($this_condition and $that_condition and $this_other_long_condition) { # do something } -------------- open(FOO,$foo) or die "Can't open $foo: $!"; -------------- die "Can't open $foo: $!" unless open(FOO,$foo); -------------- print "Starting analysis\n" if $verbose; -------------- $verbose and print "Starting analysis\n"; -------------- return print reverse sort num values %array; return print(reverse(sort num (values(%array)))); -------------- LINE: for (;;) { statements; last LINE if $foo; next LINE if /^#/; statements; } -------------- $ALL_CAPS_HERE # constants only (beware clashes with Perl vars!) $Some_Caps_Here # package-wide global/static $no_caps_here # function scope my() or local() variables -------------- $IDX = $ST_MTIME; $IDX = $ST_ATIME if $opt_u; $IDX = $ST_CTIME if $opt_c; $IDX = $ST_SIZE if $opt_s; mkdir $tmpdir, 0700 or die "can't mkdir $tmpdir: $!"; chdir($tmpdir) or die "can't chdir $tmpdir: $!"; mkdir 'tmp', 0777 or die "can't mkdir $tmpdir/tmp: $!"; -------------- opendir(D, $dir) or die "Can't opendir $dir: $!"; -------------- tr [abc] [xyz]; ############################### 24:Common Practices/Fluent Perl ############################### return bless $mess => $class; -------------- sub foo () { "FOO" } sub bar () { "BAR" } print foo => bar; # prints fooBAR, not FOOBAR; -------------- join(", " => @array); -------------- for (@lines) { $_ .= "\n"; } -------------- $_ .= "\n" for @lines; -------------- %cache = map { $_ => expensive($_) } @common_args; $xval = $cache{$x} || expensive($x); -------------- while (<>) { next if /^=for\s+(index|later)/; $chars += length; $words += split; $lines += y/\n//; } -------------- @haslen = grep { length } @random; -------------- for ($episode) { s/fred/barney/g; s/wilma/betty/g; s/pebbles/bambam/g; } -------------- sub bark { my Dog $spot = shift; my $quality = shift || "yapping"; my $quantity = shift || "nonstop"; ... } -------------- $xval = $cache{$x} ||= expensive($x); -------------- while (<>) { $comments++, next if /^#/; $blank++, next if /^\s*$/; last if /^__END__/; $code++; } print "comment = $comments\nblank = $blank\ncode = $code\n"; -------------- while (<>) { /^#/ and $comments++, next; /^\s*$/ and $blank++, next; /^__END__/ and last; $code++; } print "comment = $comments\nblank = $blank\ncode = $code\n"; -------------- #!/usr/bin/perl -n $comments++, next LINE if /#/; $blank++, next LINE if /^\s*$/; last LINE if /^__END__/; $code++; END { print "comment = $comments\nblank = $blank\ncode = $code\n" } -------------- END { print <<"COUNTS" } comment = $comments blank = $blank code = $code COUNTS -------------- ($new = $old) =~ s/bad/good/g; -------------- chomp($answer = ); -------------- for (@new = @old) { s/bad/good/g } -------------- sub bark { my DOG $spot = shift; my %parm = @_; my $quality = $parm{QUALITY} || "yapping"; my $quantity = $parm{QUANTITY} || "nonstop"; ... } $fido->bark( QUANTITY => "once", QUALITY => "woof" ); -------------- #!/usr/bin/perl -p 1 while s/^(.*?)(\t+)/$1 . ' ' x (length($2) * 4 - length($1) % 4)/e; -------------- #!/usr/bin/perl -p 1 while s{ ^ # anchor to beginning ( # start first subgroup .*? # match minimal number of characters ) # end first subgroup ( # start second subgroup \t+ # match one or more tabs ) # end second subgroup } { my $spacelen = length($2) * 4; # account for full tabs $spacelen -= length($1) % 4; # account for the uneven tab $1 . ' ' x $spacelen; # make correct number of spaces }ex; -------------- 1 while s/(\t+)/' ' x (length($1) * 4 - length($`) % 4)/e; -------------- 1 while s/\t+/' ' x (($+[0] - $-[0]) * 4 - $-[0] % 4)/e; -------------- sub is_valid_pattern { my $pat = shift; return eval { "" =~ /$pat/; 1 } || 0; } -------------- use XML::Parser; $p = new XML::Parser Style => 'subs'; setHandlers $p Char => sub { $out[-1] .= $_[1] }; push @out, ""; sub literal { $out[-1] .= "C<"; push @out, ""; } sub literal_ { my $text = pop @out; $out[-1] .= $text . ">"; } ... -------------- my %seen; while (<>) { my ($a, $b, $c, $d) = split; print unless $seen{$a}{$b}{$c}{$d}++; } if (my $tmp = $seen{fee}{fie}{foe}{foo}) { printf qq(Saw "fee fie foe foo" [sic] %d time%s.\n"), $tmp, $tmp == 1 ? "" : "s"; } ##################################################################################### 24:Common Practices/Fluent Perl/Program Generation/Generating other languages in Perl ##################################################################################### print &q(<<"EOT"); : #!$bin/perl : eval 'exec $bin/perl -S \$0 \${1+"\$@"}' : if \$running_under_some_shell; : EOT -------------- print <<"XML"; blah blah blah ${ \( I ) } blah blah blah blah blah blah @{[ I ]} blah blah blah XML ##################################################################################### 24:Common Practices/Fluent Perl/Program Generation/Generating Perl in other languages ##################################################################################### % perl # line 2000 "Odyssey" # the "#" on the previous line must be the first char on line warn "pod bay doors"; # or die ^D pod bay doors at Odyssey line 2001. -------------- # line 1996 "Odyssey" eval qq{ #line 2025 "Hal" die "pod bay doors"; }; print "Problem with $@"; warn "I'm afraid I can't do that"; ^D I'm afraid I can't do that at Odyssey line 2001. Problem with pod bay doors at Hal line 2025. ################################################################# 24:Common Practices/Fluent Perl/Program Generation/Source filters ################################################################# #!/usr/bin/perl use MyDecryptFilter; @*x$]`0uN&k^Zx02jZ^X{.?s!(f;9Q/^A^@~~8H]|,%@^P:q-= ... -------------- #!/usr/bin/perl use Filter::exec "a2p"; # the awk-to-perl translator 1,30 { print $1 } ################################# 25:Writing Portable Perl/Newlines ################################# print SOCKET "Hi there, client!\015\012"; # right print SOCKET "Hi there, client!\r\n"; # wrong -------------- use Socket qw(:DEFAULT :crlf); print SOCKET "Hi there, client!$CRLF" # right -------------- use Socket qw(:DEFAULT :crlf); local ($/) = LF; # not needed if $/ is already \012 while () { s/$CR?$LF/\n/; # replace LF or CRLF with logical newline } -------------- $data =~ s/\015?\012/\n/g; return $data; #################################################### 25:Writing Portable Perl/Endianness and Number Width #################################################### print unpack("h*", pack("s2", 1, 2)), "\n"; # '10002000' on e.g. Intel x86 or Alpha 21064 in little-endian mode # '00100020' on e.g. Motorola 68040 -------------- $is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; $is_little_endian = unpack("h*", pack("s", 1)) =~ /^1/; ############################################## 25:Writing Portable Perl/Files and Filesystems ############################################## use File::Spec::Functions; chdir( updir() ); # go up one directory $file = catfile( curdir(), 'temp', 'file.txt' ); -------------- open(FILE, $existing_file) or die $!; # wrongish open(FILE, "<$existing_file") or die $!; # righter open(FILE, "<", $existing_file) or die $!; # righterer ######################################################### 25:Writing Portable Perl/Interprocess Communication (IPC) ######################################################### open(MAIL, '|/usr/lib/sendmail -t') or die "cannot fork sendmail: $!"; ######################################## 25:Writing Portable Perl/Dates and Times ######################################## require Time::Local; $offset = Time::Local::timegm(0, 0, 0, 1, 0, 70); ############################################ 26:Plain Old Documentation/Pod in a Nutshell ############################################ =head1 Here There Be Pods! -------------- =item snazzle The snazzle() function will behave in the most spectacular form that you can possibly imagine, not even excepting cybernetic pyrotechnics. =cut sub snazzle { my $arg = shift; .... } =item razzle The razzle() function enables autodidactic epistemology generation. =cut sub razzle { print "Epistemology generation unimplemented on this platform.\n"; } -------------- print "got 1\n"; =for commentary This paragraph alone is ignored by anyone except the mythical "commentary" translator. When it's over, you're still in pod mode, not program mode. print "got 2\n"; =cut # ok, real program again print "got 3\n"; =begin comment { print "got 4\n"; all of this stuff here will be ignored by everyone print "got 5\n"; =end comment } =cut print "got 6\n"; ########################################################### 26:Plain Old Documentation/Pod in a Nutshell/Pod Directives ########################################################### =over 4 =item * Mithril armor =item * Elven cloak =back -------------- =over 4 =item 1. First, speak "friend". =item 2. Second, enter Moria. =back -------------- =over 4 =item armor() Description of the armor() function =item chant() Description of the chant() function =back -------------- =for html

This is a raw HTML paragraph

-------------- =begin html
Figure 1.
=end html =begin text --------------- | foo | | bar | --------------- ^^^^ Figure 1. ^^^^ =end text ###################################################### 26:Plain Old Documentation/Pod Translators and Modules ###################################################### % pod2text File.pm | less -------------- % pod2man File.pm | nroff -man | less -------------- % pod2man File.pm | troff -man -Tps -t > tmppage.ps % ghostview tmppage.ps -------------- % lpr -Ppostscript tmppage.ps -------------- % pod2html File.pm > tmppage.html % lynx tmppage.html % netscape -remote "openURL(file:`pwd`/tmppage.html)" -------------- This is a $variable right here -------------- This is a $variable right here -------------- $a=3; =secret stuff warn "Neither POD nor CODE!?" =cut back print "got $a\n"; ##################################################### 26:Plain Old Documentation/Writing Your Own Pod Tools ##################################################### #!/usr/bin/perl -l00n # olpod - outline pod next unless /^=head/; s/^=head(\d)\s+/ ' ' x ($1 * 4 - 4)/e; print $_, "\n"; -------------- #!/usr/bin/perl -00 # catpod - cat out just the pods while (<>) { if (! $inpod) { $inpod = /^=/; } if ($inpod) { $inpod = !/^=cut/; print; } } continue { if (eof) { close ARGV; $inpod = ''; } } -------------- % catpod MyModule.pm | wc -------------- #!/usr/bin/perl -n00 # podlit - print the indented literal blocks from pod input print if /^\s/; -------------- % catpod MyModule.pm | podlit | grep funcname -------------- #!/usr/bin/perl # catpod2, class and program package catpod_parser; use Pod::Parser; @ISA = qw(Pod::Parser); sub command { my ($parser, $command, $paragraph, $line_num) = @_; my $out_fh = $parser->output_handle(); $paragraph .= "\n" unless substr($paragraph, -1) eq "\n"; $paragraph .= "\n" unless substr($paragraph, -2) eq "\n\n"; print $out_fh "=$command $paragraph"; } sub verbatim { my ($parser, $paragraph, $line_num) = @_; my $out_fh = $parser->output_handle(); print $out_fh $paragraph; } sub textblock { my ($parser, $paragraph, $line_num) = @_; my $out_fh = $parser->output_handle(); print $out_fh $paragraph; } sub interior_sequence { my ($parser, $seq_command, $seq_argument) = @_; return "$seq_command<$seq_argument>"; } if (!caller) { package main; my $parser = catpod_parser::->new(); unshift @ARGV, '-' unless @ARGV; for (@ARGV) { $parser->parse_from_file($_); } } 1; __END__ =head1 NAME docs describing the new catpod program here ######################################################### 26:Plain Old Documentation/Documenting Your Perl Programs ######################################################### Copyright 2013, Randy Waterhouse. All Rights Reserved. -------------- This program is free software. You may copy or redistribute it under the same terms as Perl itself. -------------- __END__ =head1 NAME Modern - I am the very model of a modern major module ########################### 27:Perl Culture/Perl Poetry ########################### Article 970 of comp.lang.perl: Path: jpl-devvax!pl-dexxav!lwall From: lwall@jpl-dexxav.JPL.NASA.GOV (Larry Wall) Newsgroups: news.groups,rec.arts.poems,comp.lang.perl Subject: CALL FOR DISCUSSION: comp.lang.perl.poems Message-ID: <0401@jpl-devvax.JPL.NASA.GOV> Date: 1 Apr 90 00:00:00 GMT Reply-To: lwall@jpl-devvax.JPL.NSAS.GOV (Larry Wall) Organization: Jet Prepulsion Laboratory, Pasadena, CA Lines: 61 It has come to my attention that there is a crying need for a place for people to express both their emotional and technical natures simultaneously. Several people have sent me some items which don't fit into any newsgroup. Perhaps it's because I recently posted to both comp.lang.perl and to rec.arts.poems, but people seem to be writing poems in Perl, and they're asking me where they should post them. Here is a sampling: From a graduate student (in finals week), the following haiku: study, write, study, do review (each word) if time. close book. sleep? what's that? And someone writing from Fort Lauderdale writes: sleep, close together, sort of sin each spring & wait; 50% die A person who wishes to remain anonymous wrote the following example of "Black Perl". (The Pearl poet would have been shocked, no doubt.) BEFOREHAND: close door, each window & exit; wait until time. open spellbook, study, read (scan, select, tell us); write it, print the hex while each watches, reverse its length, write again; kill spiders, pop them, chop, split, kill them. unlink arms, shift, wait & listen (listening, wait), sort the flock (then, warn the "goats" & kill the "sheep"); kill them, dump qualms, shift moralities, values aside, each one; die sheep! die to reverse the system you accept (reject, respect); next step, kill the next sacrifice, each sacrifice, wait, redo ritual until "all the spirits are pleased"; do it ("as they say"). do it(*everyone***must***participate***in***forbidden**s*e*x*). return last victim; package body; exit crypt (time, times & "half a time") & close it, select (quickly) & warn your next victim; AFTERWORDS: tell nobody. wait, wait until time; wait until next year, next decade; sleep, sleep, die yourself, die at last I tried that, and it actually parses in Perl. It doesn't appear to do anything useful, however. I think I'm glad, actually... I hereby propose the creation of comp.lang.perl.poems as a place for such items, so we don't clutter the perl or poems newsgroups with things that may be of interest to neither. Or, alternately, we should create rec.arts.poems.perl for items such as those above which merely parse, and don't do anything useful. (There is precedent in rec.arts.poems, after all.) Then also create comp.lang.perl.poems for poems that actually do something, such as this haiku of my own: print STDOUT q Just another Perl hacker, unless $spring Larry Wall lwall@jpl-devvax.jpl.nasa.gov -------------- #!/usr/bin/perl APPEAL: listen (please, please); open yourself, wide; join (you, me), connect (us,together), tell me. do something if distressed; @dawn, dance; @evening, sing; read (books,$poems,stories) until peaceful; study if able; write me if-you-please; sort your feelings, reset goals, seek (friends, family, anyone); do*not*die (like this) if sin abounds; keys (hidden), open (locks, doors), tell secrets; do not, I-beg-you, close them, yet. accept (yourself, changes), bind (grief, despair); require truth, goodness if-you-will, each moment; select (always), length(of-days) # listen (a perl poem) # Sharon Hopkins # rev. June 19, 1995 ######################################################## 28:Special Names/Special Variables in Alphabetical Order ######################################################## while (<>) {...} # equivalent only in unadorned while test while (defined($_ = <>)) {...} chomp chomp($_) /^Subject:/ $_ =~ /^Subject:/ tr/a-z/A-Z/ $_ =~ tr/a-z/A-Z/ -------------- $) = "5 5"; -------------- $< = $>; # set real to effective uid ($<,$>) = ($>,$<); # swap real and effective uid -------------- $ENV{PATH} = "/bin:/usr/bin"; $ENV{PAGER} = "less"; $ENV{LESS} = "MQeicsnf"; # our favorite switches to less(1) system "man perl"; # picks up new settings -------------- die if $@; -------------- % perl -MLWP::Simple -le 'print $INC{"LWP/Simple.pm"}' /opt/perl/5.6.0/lib/site_perl/LWP/Simple.pm -------------- /usr/local/lib/perl5/5.6.0/sun4-solaris /usr/local/lib/perl5/5.6.0 /usr/local/lib/perl5/site_perl/5.6.0/sun4-solaris /usr/local/lib/perl5/site_perl/5.6.0 /usr/local/lib/perl5/site_perl/5.00552/sun4-solaris /usr/local/lib/perl5/site_perl/5.00552 /usr/local/lib/perl5/site_perl/5.005/sun4-solaris /usr/local/lib/perl5/site_perl/5.005 /usr/local/lib/perl5/site_perl -------------- use lib "/mypath/libdir/"; use SomeMod; -------------- % perl -i.orig -pe 's/foo/bar/g' *.c -------------- local $^I = '.orig'; local @ARGV = glob("*.c"); while (<>) { s/foo/bar/g; print; } -------------- undef $/; # enable whole-file mode $_ = ; # whole file now here s/\n[ \t]+/ /g; # fold indented lines -------------- undef $/; while (<>) { # $_ has the whole next file in it ... } -------------- $/ = \32768; # or \"32768" or \$scalar_var_containing_32768 open(FILE, $myfile); $record = ; -------------- $rev = $+ if /Version: (.*)|Revision: (.*)/; -------------- $^M = 'a' x (1 << 16); -------------- warn "No checksumming!\n" if $] < 3.019; die "Must have prototyping available\n" if $] < 5.003; -------------- printf "%vd", $^V; -------------- warn "No `our' declarations!\n" if $^V and $^V lt v5.6; -------------- $_ = 'abcdefghi'; /def/; print "$`:$&:$'\n"; # prints abc:def:ghi -------------- $_ = 'abcdefghi'; /(.*?)(def)(.*)/s; # /s in case $1 contains newlines print "$1:$2:$3\n"; # prints abc:def:ghi -------------- sub handler { my $sig = shift; # 1st argument is signal name syswrite STDERR, "Caught a SIG$sig--shutting down\n"; # Avoid standard I/O in async handlers to suppress # core dumpage. (Should avoid string concat too.) close LOG; # This calls standard I/O, so may dump core anyway! exit 1; # But since we're exiting, no harm in trying. } $SIG{INT} = \&handler; $SIG{QUIT} = \&handler; ... $SIG{INT} = 'DEFAULT'; # restore default action $SIG{QUIT} = 'IGNORE'; # ignore SIGQUIT -------------- $SIG{PIPE} = "Plumber"; # okay, assumes main::Plumber $SIG{PIPE} = \&Plumber; # fine, assume current Plumber -------------- local $SIG{__WARN__} = sub { die $_[0] }; eval $proggie; -------------- use warnings qw/FATAL all/; eval $proggie; -------------- $foo{$a,$b,$c} -------------- $foo{join($;, $a, $b, $c)} -------------- @foo{$a,$b,$c} # a slice--note the @ -------------- ($foo{$a},$foo{$b},$foo{$c}) -------------- { local $^F = 10_000; pipe(HITHER,THITHER) or die "can't pipe: $!"; } ############ 29:Functions ############ print 1+2*4; # Prints 9. print(1+2) * 4; # Prints 3! print (1+2)*4; # Also prints 3! print +(1+2)*4; # Prints 12. print ((1+2)*4); # Prints 12. -------------- chmod 0644, @array; -------------- unshift @array, 0644; chmod @array; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/abs ##################################################### $diff = abs($first - $second); -------------- my $diff = abs($first - $second); ######################################################## 29:Functions/Perl Functions in Alphabetical Order/accept ######################################################## unless ($peer = accept(Client, Server)) { die "Can't accept a connection: $!\n"; } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/alarm ####################################################### print "Answer me within one minute, or die: "; alarm(60); # kill program in one minute $answer = ; $timeleft = alarm(0); # clear alarm print "You had $timeleft seconds remaining\n"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/atan2 ####################################################### $pi = atan2(1,1) * 4; -------------- sub tan { sin($_[0]) / cos($_[0]) } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/bind ###################################################### use Socket; $port_number = 80; # pretend we want to be a web server $sockaddr = sockaddr_in($port_number, INADDR_ANY); bind S, $sockaddr or die "Can't bind $port_number: $!\n"; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/binmode ######################################################### binmode STDOUT; open(GIF, "vim-power.gif") or die "Can't open vim-power.gif: $!\n"; binmode GIF; while (read(GIF, $buf, 1024)) { print STDOUT $buf; } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/bless ####################################################### $pet = Beast->new(TYPE => "cougar", NAME => "Clyde"); # then in Beast.pm: sub new { my $class = shift; my %values = @_; my $self = { %values }; return bless($self, $class); } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/caller ######################################################## ($package, $filename, $line) = caller; -------------- sub careful { my ($package, $filename) = caller; unless ($package eq __PACKAGE__ && $filename eq __FILE__) { die "You weren't supposed to call me, $package!\n"; } print "called me safely\n"; } sub safecall { careful(); } -------------- $i = 0; while (($package, $filename, $line, $subroutine, $hasargs, $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller($i++) ) { ... } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/chdir ####################################################### chdir "$prefix/lib" or die "Can't cd to $prefix/lib: $!\n"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/chmod ####################################################### $cnt = chmod 0755, 'file1', 'file2'; -------------- chmod(0755, @executables) == @executables or die "couldn't chmod some of @executables: $!"; -------------- @cannot = grep {not chmod 0755, $_} 'file1', 'file2', 'file3'; die "$0: could not chmod @cannot\n" if @cannot; -------------- $DEF_MODE = 0644; # Can't use quotes here! PROMPT: { print "New mode? "; $strmode = ; exit unless defined $strmode; # test for eof if ($strmode =~ /^\s*$/) { # test for blank line $mode = $DEF_MODE; } elsif ($strmode !~ /^\d+$/) { print "Want numeric mode, not $strmode\n"; redo PROMPT; } else { $mode = oct($strmode); # converts "755" to 0755 } chmod $mode, @files; } -------------- use Fcntl ':mode'; chmod S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, @executables; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/chomp ####################################################### while () { chomp; # avoid \n on last field @array = split /:/; ... } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/chop ###################################################### @lines = `cat myfile`; chop @lines; -------------- chop($cwd = `pwd`); chop($answer = ); -------------- $answer = chop($tmp = ); # WRONG -------------- $answer = substr , 0, -1; -------------- chop($answer = ); -------------- $last_char = chop($var); $last_char = substr($var, -1, 1, ''); # same thing -------------- substr($caravan, -5) = ""; -------------- $tail = substr($caravan, -5, 5, ""); ####################################################### 29:Functions/Perl Functions in Alphabetical Order/chown ####################################################### chown($uidnum, $gidnum, 'file1', 'file2') == 2 or die "can't chown file1 or file2: $!"; -------------- chown($uidnum, $gidnum, @filenames) == @filenames or die "can't chown @filenames: $!"; -------------- sub chown_by_name { my($user, $pattern, @files) = @_; chown((getpwnam($user))[2,3], @files) == @files or die "can't chown @files: $!"; } chown_by_name("fred", glob("*.c")); -------------- use POSIX qw(sysconf _PC_CHOWN_RESTRICTED); # only try if we're the superuser or on a permissive system if ($> == 0 || !sysconf(_PC_CHOWN_RESTRICTED) ) { chown($uidnum, -1, $filename) or die "can't chown $filename to $uidnum: $!"; } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/chroot ######################################################## chroot((getpwnam('ftp'))[7]) or die "Can't do anonymous ftp: $!\n"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/close ####################################################### open(OUTPUT, '| sort -rn | lpr -p') # pipe to sort and lpr or die "Can't start sortlpr pipe: $!"; print OUTPUT @lines; # print stuff to output close OUTPUT # wait for sort to finish or warn $! ? "Syserr closing sortlpr pipe: $!" : "Wait status $? from sortlpr pipe"; -------------- open(NETSTAT, "netstat -rn |") or die "can't run netstat: $!"; open(STDIN, "<&NETSTAT") or die "can't dup to stdin: $!"; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/connect ######################################################### use Socket; my ($remote, $port) = ("www.perl.com", 80); my $destaddr = sockaddr_in($port, inet_aton($remote)); connect SOCK, $destaddr or die "Can't connect to $remote at port $port: $!"; ############################################################################################################ 29:Functions/Perl Functions in Alphabetical Order/cos C<$_> ############################################################################################################ # Here's the lazy way of getting degrees-to-radians. $pi = atan2(1,1) * 4; $piover180 = $pi/180; # Print table. for ($deg = 0; $deg <= 90; $deg++) { printf "%3d %7.5f\n", $deg, cos($deg * $piover180); } -------------- sub acos { atan2( sqrt(1 - $_[0] * $_[0]), $_[0] ) } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/crypt ####################################################### $pwd = (getpwuid ($<))[1]; # Assumes we're on Unix. system "stty -echo"; # or look into Term::ReadKey on CPAN print "Password: "; chomp($word = ); print "\n"; system "stty echo"; if (crypt($word, $pwd) ne $pwd) { die "Sorry...\n"; } else { print "ok\n"; } ######################################################### 29:Functions/Perl Functions in Alphabetical Order/dbmopen ######################################################### use DB_File; dbmopen(%NS_Hist, "$ENV{HOME}/.netscape/history.dat", undef) or die "Can't open netscape history file: $!"; while (($url, $when) = each %NS_Hist) { next unless defined($when); chop ($url, $when); # kill trailing null bytes printf "Visited %s at %s.\n", $url, scalar(localtime(unpack("V",$when))); } -------------- $alias = $aliases{"postmaster\0"}; chop $alias; # kill the null ######################################################### 29:Functions/Perl Functions in Alphabetical Order/defined ######################################################### print if defined $switch{D}; -------------- print "$val\n" while defined($val = pop(@ary)); -------------- setpwent(); while (defined($name = getpwent())) { print "<<$name>>\n"; } endpwent(); -------------- die "Can't readlink $sym: $!" unless defined($value = readlink $sym); -------------- indir("funcname", @arglist); sub indir { my $subname = shift; no strict 'refs'; # so we can use subname indirectly if (defined &$subname) { &$subname(@_); # or $subname->(@_); } else { warn "Ignoring call to invalid function $subname"; } } -------------- if (@an_array) { print "has array elements\n" } if (%a_hash) { print "has hash members\n" } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/delete ######################################################## # set up array of array of hash $dungeon[$x][$y] = \%properties; # delete one property from hash delete $dungeon[$x][$y]{"OCCUPIED"}; # delete three properties all at once from hash delete @{ $dungeon[$x][$y] }{ "OCCUPIED", "DAMP", "LIGHTED" }; # delete reference to %properties from array delete $dungeon[$x][$y]; -------------- foreach $key (keys %hash) { delete $hash{$key}; } -------------- delete @hash{keys %hash}; -------------- %hash = (); # completely empty %hash undef %hash; # forget %hash ever existed -------------- foreach $index (0 .. $#array) { delete $array[$index]; } -------------- delete @array[0 .. $#array]; -------------- @array = (); # completely empty @array undef @array; # forget @array ever existed ##################################################### 29:Functions/Perl Functions in Alphabetical Order/die ##################################################### eval { ... }; die unless $@ =~ /Expected exception/; -------------- die "/usr/games is no good"; die "/usr/games is no good, stopped"; -------------- die '"', __FILE__, '", line ', __LINE__, ", phooey on you!\n"; -------------- die "Can't cd to spool: $!\n" unless chdir '/usr/spool/news'; chdir '/usr/spool/news' or die "Can't cd to spool: $!\n" ########################################################### 29:Functions/Perl Functions in Alphabetical Order/do (file) ########################################################### do 'stat.pl'; -------------- scalar eval `cat stat.pl`; # or `type stat.pl`, on Windows -------------- # read in config files: system first, then user for $file ("/usr/share/proggie/defaults.rc", "$ENV{HOME}/.someprogrc") { unless ($return = do $file) { warn "couldn't parse $file: $@" if $@; warn "couldn't do $file: $!" unless defined $return; warn "couldn't run $file" unless $return; } } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/each ###################################################### while (($key,$value) = each %ENV) { print "$key=$value\n"; } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/eof ##################################################### while (<>) { if (eof()) { print "-" x 30, "\n"; } print; } -------------- # reset line numbering on each input file while (<>) { next if /^\s*#/; # skip comments print "$.\t$_"; } continue { close ARGV if eof; # Not eof()! } -------------- while (<>) { print if /pattern/ .. eof; } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/eval ###################################################### eval { ... }; # trap runtime errors if ($@) { ... } # handle error -------------- print "\nEnter some perl code: "; while () { eval; print $@; print "\nEnter some more perl code: "; } -------------- #!/usr/bin/perl # rename - change filenames $op = shift; for (@ARGV) { $was = $_; eval $op; die if $@; # next line calls the built-in function, # not the script by the same name rename($was,$_) unless $was eq $_; } -------------- $ rename 's/\.orig$//' *.orig $ rename 'y/A-Z/a-z/ unless /^Make/' * $ rename '$_ .= ".bad"' *.f -------------- # make divide-by-zero non-fatal eval { $answer = $a / $b; }; warn $@ if $@; # same thing, but less efficient if run multiple times eval '$answer = $a / $b'; warn $@ if $@; # a compile-time syntax error (not trapped) eval { $answer = }; # WRONG # a run-time syntax error eval '$answer ='; # sets $@ ###################################################### 29:Functions/Perl Functions in Alphabetical Order/exec ###################################################### exec 'echo', 'Your arguments are: ', @ARGV; -------------- exec "sort $outfile | uniq" or die "Can't do sort/uniq: $!\n"; -------------- $editor = "/usr/bin/vi"; exec $editor "view", @files # trigger read-only mode or die "Couldn't execute $editor: $!\n"; -------------- exec { "/usr/bin/vi" }, "view", @files # trigger read-only mode or die "Couldn't execute $editor: $!\n"; -------------- @args = ("echo surprise"); # just one element in list exec @args # still subject to shell escapes or die "exec: $!"; # because @args == 1 -------------- exec { $args[0] } @args # safe even with one-argument list or die "can't exec @args: $!"; -------------- exec ('foo') or print STDERR "couldn't exec foo: $!"; { exec ('foo') }; print STDERR "couldn't exec foo: $!"; ######################################################## 29:Functions/Perl Functions in Alphabetical Order/exists ######################################################## print "True\n" if $hash{$key}; print "Defined\n" if defined $hash{$key}; print "Exists\n" if exists $hash{$key}; print "True\n" if $array[$index]; print "Defined\n" if defined $array[$index]; print "Exists\n" if exists $array[$index]; -------------- if (exists $hash{A}{B}{$key}) { ... } -------------- undef $ref; if (exists $ref->{"Some key"}) { } print $ref; # prints HASH(0x80d3d5c) -------------- if ($ref and exists $ref->[$x] and exists $ref->[$x][$y] and exists $ref->[$x][$y]{$key} and exists $ref->[$x][$y]{$key}[2] ) { ... } -------------- sub flub; print "Exists\n" if exists &flub; print "Defined\n" if defined &flub; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/exit ###################################################### $ans = ; exit if $ans =~ /^[Xx]/; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/exp ##################################################### use Math::Complex; print -exp(1) ** (i * pi); # prints 1 ####################################################### 29:Functions/Perl Functions in Alphabetical Order/fcntl ####################################################### use Fcntl; -------------- use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); $flags = fcntl(REMOTE, F_GETFL, 0) or die "Can't get flags for the socket: $!\n"; $flags = fcntl(REMOTE, F_SETFL, $flags | O_NONBLOCK) or die "Can't set flags for the socket: $!\n"; -------------- $retval = fcntl(...) || -1; printf "fcntl actually returned %d\n", $retval; ######################################################## 29:Functions/Perl Functions in Alphabetical Order/fileno ######################################################## if (fileno(THIS) == fileno(THAT)) { print "THIS and THAT are dups\n"; } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/flock ####################################################### use Fcntl qw/:flock/; # import LOCK_* constants sub mylock { flock(MBOX, LOCK_EX) or die "can't lock mailbox: $!"; # in case someone appended while we were waiting # and our stdio buffer is out of sync seek(MBOX, 0, 2) or die "can't seek to the end of mailbox: $!"; } open(MBOX, ">>/usr/spool/mail/$ENV{'USER'}") or die "can't open mailbox: $!"; mylock(); print MBOX $msg, "\n\n"; close MBOX or die "can't close mailbox: $!"; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/fork ###################################################### use Errno qw(EAGAIN); FORK: { if ($pid = fork) { # parent here # child process pid is available in $pid } elsif (defined $pid) { # $pid is zero here if defined # child here # parent process pid is available with getppid } elsif ($! == EAGAIN) { # EAGAIN is the supposedly recoverable fork error sleep 5; redo FORK; } else { # weird fork error die "Can't fork: $!\n"; } } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/format ######################################################## my $str = "widget"; # Lexically scoped variable. format Nice_Output = Test: @<<<<<<<< @||||| @>>>>> $str, $%, '$' . int($num) . local $~ = "Nice_Output"; # Select our format. local $num = $cost * $quantity; # Dynamically scoped variable. write; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/getc ###################################################### if ($BSD_STYLE) { system "stty cbreak /dev/tty 2>&1"; } else { system "stty", "-icanon", "eol", "\001"; } $key = getc; if ($BSD_STYLE) { system "stty -cbreak /dev/tty 2>&1"; } else { system "stty", "icanon", "eol", "^@"; # ASCII NUL } print "\n"; ########################################################## 29:Functions/Perl Functions in Alphabetical Order/getgrent ########################################################## ($name, $passwd, $gid, $members) -------------- while (($name, $passwd, $gid) = getgrent) { $gid{$name} = $gid; } ############################################################### 29:Functions/Perl Functions in Alphabetical Order/gethostbyaddr ############################################################### ($name, $aliases, $addrtype, $length, @addrs) = gethostbyaddr($packed_binary_address, $addrtype); -------------- ($a, $b, $c, $d) = unpack('C4', $addrs[0]); -------------- $dots = sprintf "%vd", $addrs[0]; -------------- use Socket; $printable_address = inet_ntoa($addrs[0]); -------------- use Socket; $ipaddr = inet_aton("127.0.0.1"); # localhost $claimed_hostname = gethostbyaddr($ipaddr, AF_INET); -------------- $ipaddr = v127.0.0.1; ############################################################### 29:Functions/Perl Functions in Alphabetical Order/gethostbyname ############################################################### ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname($remote_hostname); -------------- ($a, $b, $c, $d) = unpack('C4', $addrs[0]); -------------- $dots = sprintf "%vd", $addrs[0]; -------------- use Socket; $ipaddr = gethostbyname($remote_host); printf "%s has address %s\n", $remote_host, inet_ntoa($ipaddr); ############################################################ 29:Functions/Perl Functions in Alphabetical Order/gethostent ############################################################ ($name, $aliases, $addrtype, $length, @addrs) -------------- ($a, $b, $c, $d) = unpack('C4', $addrs[0]); ########################################################## 29:Functions/Perl Functions in Alphabetical Order/getlogin ########################################################## $login = getlogin() || (getpwuid($<))[0] || "Intruder!!"; ############################################################## 29:Functions/Perl Functions in Alphabetical Order/getnetbyaddr ############################################################## use Socket; ($name, $aliases, $addrtype, $net) = getnetbyaddr(127, AF_INET); ############################################################## 29:Functions/Perl Functions in Alphabetical Order/getnetbyname ############################################################## ($name, $aliases, $addrtype, $net) = getnetbyname("loopback"); ########################################################### 29:Functions/Perl Functions in Alphabetical Order/getnetent ########################################################### ($name, $aliases, $addrtype, $net) = getnetent(); ############################################################# 29:Functions/Perl Functions in Alphabetical Order/getpeername ############################################################# use Socket; $hersockaddr = getpeername SOCK; ($port, $heraddr) = sockaddr_in($hersockaddr); $herhostname = gethostbyaddr($heraddr, AF_INET); $herstraddr = inet_ntoa($heraddr); ############################################################# 29:Functions/Perl Functions in Alphabetical Order/getpriority ############################################################# $curprio = getpriority(0, 0); ################################################################ 29:Functions/Perl Functions in Alphabetical Order/getprotobyname ################################################################ ($name, $aliases, $protocol_number) = getprotobyname("tcp"); ################################################################## 29:Functions/Perl Functions in Alphabetical Order/getprotobynumber ################################################################## ($name, $aliases, $protocol_number) = getprotobynumber(6); ############################################################# 29:Functions/Perl Functions in Alphabetical Order/getprotoent ############################################################# ($name, $aliases, $protocol_number) = getprotoent(); ########################################################## 29:Functions/Perl Functions in Alphabetical Order/getpwent ########################################################## ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwent(); -------------- while (($name, $passwd, $uid) = getpwent()) { $uid{$name} = $uid; } ########################################################## 29:Functions/Perl Functions in Alphabetical Order/getpwnam ########################################################## ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwnam("daemon"); ########################################################## 29:Functions/Perl Functions in Alphabetical Order/getpwuid ########################################################## ($name,$passwd,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwuid(2); ############################################################### 29:Functions/Perl Functions in Alphabetical Order/getservbyname ############################################################### ($name, $aliases, $port_number, $protocol_name) = getservbyname("www", "tcp"); ############################################################### 29:Functions/Perl Functions in Alphabetical Order/getservbyport ############################################################### ($name, $aliases, $port_number, $protocol_name) = getservbyport(80, "tcp"); ############################################################ 29:Functions/Perl Functions in Alphabetical Order/getservent ############################################################ ($name, $aliases, $port_number, $protocol_name) = getservent(); ############################################################# 29:Functions/Perl Functions in Alphabetical Order/getsockname ############################################################# use Socket; $mysockaddr = getsockname(SOCK); ($port, $myaddr) = sockaddr_in($mysockaddr); $myname = gethostbyaddr($myaddr,AF_INET); printf "I am %s [%vd]\n", $myname, $myaddr; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/glob ###################################################### open(MAILRC, "~/.mailrc") # WRONG: tilde is a shell thing or die "can't open ~/.mailrc: $!"; open(MAILRC, glob("~/.mailrc")) # expand tilde first or die "can't open ~/.mailrc: $!"; ######################################################## 29:Functions/Perl Functions in Alphabetical Order/gmtime ######################################################## # 0 1 2 3 4 5 6 7 8 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime; -------------- $london_month = (qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec))[(gmtime)[4]]; -------------- use POSIX qw(strftime); $now_string = strftime "%a %b %e %H:%M:%S %Y", gmtime; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/goto ###################################################### goto +("FOO", "BAR", "GLARCH")[$i]; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/grep ###################################################### @code_lines = grep !/^\s*#/, @all_lines; -------------- @list = qw(barney fred dino wilma); @greplist = grep { s/^[bfd]// } @list; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/hex ##################################################### $number = hex("ffff12c0"); -------------- sprintf "%lx", $number; # (That's an ell, not a one.) ####################################################### 29:Functions/Perl Functions in Alphabetical Order/index ####################################################### $pos = -1; while (($pos = index($string, $lookfor, $pos)) > -1) { print "Found at $pos\n"; $pos++; } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/int ##################################################### $average_age = 939/16; # yields 58.6875 (58 in C) $average_age = int 939/16; # yields 58 -------------- $n = sprintf("%.0f", $f); # round (not trunc) to nearest integer ####################################################### 29:Functions/Perl Functions in Alphabetical Order/ioctl ####################################################### require "sys/ioctl.ph"; # perhaps /usr/local/lib/perl/sys/ioctl.ph -------------- require 'sys/ioctl.ph'; $size = pack("L", 0); ioctl(FH, FIONREAD(), $size) or die "Couldn't call ioctl: $!\n"; $size = unpack("L", $size); -------------- $retval = ioctl(...) || -1; printf "ioctl actually returned %d\n", $retval; -------------- system "stty -echo"; # Works on most Unix boxen. ###################################################### 29:Functions/Perl Functions in Alphabetical Order/join ###################################################### $rec = join ':', $login,$passwd,$uid,$gid,$gcos,$home,$shell; -------------- $string = join "", @array; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/keys ###################################################### @keys = keys %ENV; # keys are in the same order as @values = values %ENV; # values, as this demonstrates while (@keys) { print pop(@keys), '=', pop(@values), "\n"; } -------------- foreach $key (sort keys %ENV) { print $key, '=', $ENV{$key}, "\n"; } -------------- foreach $key (sort { $hash{$b} <=> $hash{$a} } keys %hash) { printf "%4d %s\n", $hash{$key}, $key; } -------------- keys %hash = 1000; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/kill ###################################################### $cnt = kill 1, $child1, $child2; kill 9, @goners; kill 'STOP', getppid # Can *so* suspend my login shell... unless getppid == 1; # (But don't taunt init(8).) -------------- use Errno qw(ESRCH EPERM); if (kill 0 => $minion) { print "$minion is alive!\n"; } elsif ($! == EPERM) { # changed UID print "$minion has escaped my control!\n"; } elsif ($! == ESRCH) { print "$minion is deceased.\n"; # or zombied } else { warn "Odd; I couldn't check on the status of $minion: $!\n"; } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/last ###################################################### LINE: while () { last LINE if /^$/; # exit when done with header # rest of loop here } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/length ######################################################## $blen = do { use bytes; length $string; }; -------------- $blen = bytes::length($string); ######################################################## 29:Functions/Perl Functions in Alphabetical Order/listen ######################################################## use Socket; listen(SERVER, SOMAXCONN) or die "cannot set listen queue on SERVER: $!"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/local ####################################################### if ($sw eq '-v') { # init local array with global array local @ARGV = @ARGV; unshift @ARGV, 'echo'; system @ARGV; } # @ARGV restored -------------- # temporarily add a couple of entries to the %digits hash if ($base12) { # (NOTE: We're not claiming this is efficient!) local(%digits) = (%digits, T => 10, E => 11); parse_num(); } -------------- if ($protected) { local $SIG{INT} = 'IGNORE'; precious(); # no interrupts during this function } # previous handler (if any) restored -------------- local *MOTD; # protect any global MOTD handle my $fh = do { local *FH }; # create new indirect filehandle ########################################################### 29:Functions/Perl Functions in Alphabetical Order/localtime ########################################################### # 0 1 2 3 4 5 6 7 8 ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime; -------------- $thisday = (Sun,Mon,Tue,Wed,Thu,Fri,Sat)[(localtime)[6]]; -------------- perl -le 'print scalar localtime' ##################################################### 29:Functions/Perl Functions in Alphabetical Order/log ##################################################### sub log10 { my $n = shift; return log($n)/log(10); } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/map ##################################################### @words = map { split ' ' } @lines; -------------- @chars = map chr, @nums; -------------- %hash = map { genkey($_) => $_ } @array; -------------- %hash = (); foreach $_ (@array) { $hash{genkey($_)} = $_; } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/msgsnd ######################################################## $msg = pack "L a*", $type, $text_of_message; #################################################### 29:Functions/Perl Functions in Alphabetical Order/my #################################################### my ($friends, $romans, $countrymen) = @_; -------------- my $country = @_; # right or wrong? -------------- sub simple_as { my $self = shift; # scalar assignment my ($a,$b,$c) = @_; # list assignment ... } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/next ###################################################### LINE: while () { next LINE if /^#/; # discard comments ... } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/oct ##################################################### $val = oct $val if $val =~ /^0/; -------------- $perms = (stat("filename"))[2] & 07777; $oct_perms = sprintf "%lo", $perms; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/open ###################################################### $LOG = ">logfile"; # $LOG must not be declared my! open LOG or die "Can't open logfile: $!"; -------------- open LOG, ">logfile" || die "Can't create logfile: $!"; # WRONG open LOG, ">logfile" or die "Can't create logfile: $!"; # ok -------------- open LOG, ">logfile" or die "Can't create logfile: $!"; -------------- { my $fh; # (uninitialized) open($fh, ">logfile") # $fh is autovivified or die "Can't create logfile: $!"; ... # do stuff with $fh } # $fh closed here -------------- open my $fh, ">logfile" or die ... -------------- open(LOG, ">", "logfile") or die "Can't create logfile: $!"; -------------- open(INFO, "datafile") || die("can't open datafile: $!"); open(INFO, "< datafile") || die("can't open datafile: $!"); open(RESULTS, "> runstats") || die("can't open runstats: $!"); open(LOG, ">> logfile ") || die("can't open logfile: $!"); -------------- open INFO, "datafile" or die "can't open datafile: $!"; open INFO, "< datafile" or die "can't open datafile: $!"; open RESULTS, "> runstats" or die "can't open runstats: $!"; open LOG, ">> logfile " or die "can't open logfile: $!"; -------------- open(INPUT, "-" ) # re-open standard input for reading open(INPUT, "<-") # same thing, but explicit open(OUTPUT, ">-") # re-open standard output for writing -------------- open(DBASE, "+< database") or die "can't open existing database in update mode: $!"; -------------- open(PRINTER, "| lpr -Plp1") or die "can't fork: $!"; print PRINTER "stuff\n"; close(PRINTER) or die "lpr/close failed: $?/$!"; -------------- open(NET, "netstat -i -n |") or die "can't fork: $!"; while () { ... } close(NET) or die "can't close netstat: $!/$?"; -------------- open(PRINTER, "|-", "lpr -Plp1") or die "can't fork: $!"; open(NET, "-|", "netstat -i -n") or die "can't fork: $!"; -------------- open(PRINTER, "|-", "lpr", "-Plp1") or die "can't fork: $!"; open(NET, "-|", "netstat", "-i", "-n") or die "can't fork: $!"; -------------- defined($pid = open(FROM_CHILD, "-|")) or die "can't fork: $!"; if ($pid) { @parent_lines = ; # parent code } else { print STDOUT @child_lines; # child code } -------------- open FH, "| tr 'a-z' 'A-Z'"; # to shell command open FH, "|-", 'tr', 'a-z', 'A-Z'; # to bare command open FH, "|-" or exec 'tr', 'a-z', 'A-Z' or die; # to child -------------- open FH, "cat -n 'file' |"; # from shell command open FH, "-|", 'cat', '-n', 'file'; # from bare command open FH, "-|" or exec 'cat', '-n', 'file' or die; # from child -------------- open(SAVEOUT, ">&SAVEERR") or die "couldn't dup SAVEERR: $!"; open(MHCONTEXT, "<&4") or die "couldn't dup fd4: $!"; -------------- somefunction("&main::LOGFILE"); -------------- #!/usr/bin/perl open SAVEOUT, ">&STDOUT"; open SAVEERR, ">&STDERR"; open STDOUT, ">foo.out" or die "Can't redirect stdout"; open STDERR, ">&STDOUT" or die "Can't dup stdout"; select STDERR; $| = 1; # make unbuffered select STDOUT; $| = 1; # make unbuffered print STDOUT "stdout 1\n"; # this propagates to print STDERR "stderr 1\n"; # subprocesses too system("some command"); # uses new stdout/stderr close STDOUT; close STDERR; open STDOUT, ">&SAVEOUT"; open STDERR, ">&SAVEERR"; print STDOUT "stdout 2\n"; print STDERR "stderr 2\n"; -------------- $fd = $ENV{"MHCONTEXTFD"}; open(MHCONTEXT, "<&=$fdnum") or die "couldn't fdopen descriptor $fdnum: $!"; -------------- use Fcntl qw(F_GETFD F_SETFD); $flags = fcntl(FH, F_SETFD, 0) or die "Can't clear close-on-exec flag on FH: $!\n"; -------------- $path =~ s#^(\s)#./$1#; open (FH, "< $path\0") or die "can't open $path: $!"; -------------- open(FH, "<", $path) or die "can't open $path: $!"; -------------- use Fcntl; sysopen(FH, $path, O_RDONLY) or die "can't open $path: $!"; -------------- open(FH, "<:raw", $path) or die "can't open $path: $!"; -------------- open(FH, "<:para:crlf:uni", $path) or die "can't open $path: $!"; while ($para = ) { ... } -------------- use open IN => ":any", OUT => ":utf8"; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/our ##################################################### our Dog $spot :ears(short) :tail(long); -------------- package Foo; our $bar; # $bar is $Foo::bar for rest of lexical scope $bar = 582; package Bar; print $bar; # prints 582, just as if "our" had been "my" -------------- ($x, $y) = ("one", "two"); print "before block, x is $x, y is $y\n"; { our $x = 10; local our $y = 20; print "in block, x is $x, y is $y\n"; } print "past block, x is $x, y is $y\n"; -------------- use warnings; package Foo; our $bar; # declares $Foo::bar for rest of lexical scope $bar = 20; package Bar; our $bar = 30; # declares $Bar::bar for rest of lexical scope print $bar; # prints 30 our $bar; # emits warning ###################################################### 29:Functions/Perl Functions in Alphabetical Order/pack ###################################################### $string = pack("Cf", 244, 3.14); -------------- unpack 'C/a', "\04Gurusamy"; gives 'Guru' unpack 'a3/A* A*', '007 Bond J '; gives (' Bond','J') pack 'n/a* w/a*','hello,','world'; gives "\000\006hello,\005world" -------------- use Config; print $Config{shortsize}, "\n"; print $Config{intsize}, "\n"; print $Config{longsize}, "\n"; print $Config{longlongsize}, "\n"; -------------- struct foo { unsigned char c; float f; }; -------------- $out = pack "CCCC", 65, 66, 67, 68; # $out eq "ABCD" $out = pack "C4", 65, 66, 67, 68; # same thing -------------- $foo = pack("U4",0x24b6,0x24b7,0x24b8,0x24b9); -------------- $out = pack "CCxxCC", 65, 66, 67, 68; # $out eq "AB\0\0CD" -------------- $out = pack "s2", 1, 2; # "\1\0\2\0" on little-endian # "\0\1\0\2" on big-endian -------------- $out = pack "B32", "01010000011001010111001001101100"; $out = pack "H8", "5065726c"; # both produce "Perl" -------------- $out = pack "a4", "abcd", "x", "y", "z"; # "abcd" -------------- $out = pack "aaaa", "abcd", "x", "y", "z"; # "axyz" $out = pack "a" x 4, "abcd", "x", "y", "z"; # "axyz" -------------- $out = pack "a14", "abcdefg"; # "abcdefg\0\0\0\0\0\0\0" -------------- $out = pack "i9pl", gmtime(), $tz, $toff; -------------- $string = pack("A10" x 10, @data); -------------- $string = join(" and ", @data); $string = join("", @data); # null separator ######################################################### 29:Functions/Perl Functions in Alphabetical Order/package ######################################################### package main; $sail = "hale and hearty"; package Mizzen; $sail = "tattered"; package Whatever; print "My main sail is $main::sail.\n"; print "My mizzen sail is $Mizzen::sail.\n"; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/pipe ###################################################### pipe(README, WRITEME); unless ($pid = fork) { # child defined $pid or die "can't fork: $!"; close(README); for $i (1..5) { print WRITEME "line $i\n" } exit; } $SIG{CHLD} = sub { waitpid($pid, 0) }; close(WRITEME); @strings = ; close(README); print "Got:\n", @strings; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/pop ##################################################### $tmp = $ARRAY[$#ARRAY--]; -------------- $tmp = splice @ARRAY, -1; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/pos ##################################################### $graffito = "fee fie foe foo"; while ($graffito =~ m/e/g) { print pos $graffito, "\n"; } -------------- $graffito = "fee fie foe foo"; pos $graffito = 4; # Skip the fee, start at fie while ($graffito =~ m/e/g) { print pos $graffito, "\n"; } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/print ####################################################### print { $OK ? "STDOUT" : "STDERR" } "stuff\n"; print { $iohandle[$i] } "stuff\n"; -------------- print $a - 2; # prints $a - 2 to default filehandle (usually STDOUT) print $a (- 2); # prints -2 to filehandle specified in $a print $a -2; # also prints -2 (weird parsing rules :-) -------------- print OUT ; -------------- print OUT scalar ; -------------- print (1+2)*3, "\n"; # WRONG print +(1+2)*3, "\n"; # ok print ((1+2)*3, "\n"); # ok ###################################################### 29:Functions/Perl Functions in Alphabetical Order/push ###################################################### foreach $value (listfunc()>) { $array[++$#array] = $value; } -------------- splice @array, @array, 0, listfunc(); -------------- for (;;) { push @array, shift @array; ... } ###################################################### 29:Functions/Perl Functions in Alphabetical Order/rand ###################################################### $roll = int(rand 6) + 1; # $roll now a number between 1 and 6 ###################################################### 29:Functions/Perl Functions in Alphabetical Order/read ###################################################### while (read(FROM, $buf, 16384)) { print TO $buf; } ######################################################### 29:Functions/Perl Functions in Alphabetical Order/readdir ######################################################### opendir(THISDIR, ".") or die "serious dainbramage: $!"; @allfiles = readdir THISDIR; closedir THISDIR; print "@allfiles\n"; -------------- @allfiles = grep { $_ ne '.' and $_ ne '..' } readdir THISDIR; @allfiles = grep { not /^[.][.]?\z/ } readdir THISDIR; @allfiles = grep { not /^\.{1,2}\z/ } readdir THISDIR; @allfiles = grep !/^\.\.?\z/, readdir THISDIR; -------------- @allfiles = grep !/^\./, readdir THISDIR; -------------- @textfiles = grep -T, readdir THISDIR; -------------- opendir(THATDIR, $path) or die "can't opendir $path: $!"; @dotfiles = grep { /^\./ && -f } map { "$path/$_" } readdir(THATDIR); closedir THATDIR; ########################################################## 29:Functions/Perl Functions in Alphabetical Order/readline ########################################################## $line = ; $line = readline(STDIN); # same thing $line = readline(*STDIN); # same thing $line = readline(\*STDIN); # same thing open my $fh, "<&=STDIN" or die; bless $fh => 'AnyOldClass'; $line = readline($fh); # same thing ########################################################## 29:Functions/Perl Functions in Alphabetical Order/readlink ########################################################## readlink "/usr/local/src/express/yourself.h" ###################################################### 29:Functions/Perl Functions in Alphabetical Order/redo ###################################################### # A loop that joins lines continued with a backslash. while () { if (s/\\\n$// && defined($nextline = )) { $_ .= $nextline; redo; } print; # or whatever... } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/ref ##################################################### if (ref($r) eq "HASH") { print "r is a reference to a hash.\n"; } elsif (ref($r) eq "Hump") { # Naughty--see below. print "r is a reference to a Hump object.\n"; } elsif (not ref $r) { print "r is not a reference at all.\n"; } -------------- if ($r->isa("Hump") } print "r is a reference to a Hump object, or subclass.\n"; } ######################################################### 29:Functions/Perl Functions in Alphabetical Order/require ######################################################### require 5.6.0; # or require v5.6.0 -------------- require Socket; # instead of "use Socket;" -------------- use Socket (); -------------- require Foo::Bar; # a splendid bare name -------------- $class = 'Foo::Bar'; require $class; # $class is not a bare name -------------- require "Foo::Bar"; # quoted literal not a bare name -------------- eval "require $class"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/reset ####################################################### reset 'X'; -------------- reset 'a-z'; -------------- reset; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/reverse ######################################################### for (reverse 1 .. 10) { ... } -------------- %barfoo = reverse %foobar; ######################################################## 29:Functions/Perl Functions in Alphabetical Order/rindex ######################################################## $pos = length $string; while (($pos = rindex $string, $lookfor, $pos) >= 0) { print "Found at $pos\n"; $pos--; } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/scalar ######################################################## my ($nextvar) = scalar ; -------------- my $nextvar = ; -------------- print "Length is ", scalar(@ARRAY), "\n"; -------------- print uc(scalar(&foo,$bar)),$baz; -------------- &foo; print(uc($bar),$baz); ###################################################### 29:Functions/Perl Functions in Alphabetical Order/seek ###################################################### seek(TEST,0,1); -------------- for (;;) { while () { grok($_); # Process current line. } sleep 15; seek LOG,0,1; # Reset end-of-file error. } -------------- for (;;) { for ($curpos = tell FILE; ; $curpos = tell FILE) { grok($_); # Process current line. } sleep $for_a_while; seek FILE, $curpos, 0; # Reset end-of-file error. } ############################################################################ 29:Functions/Perl Functions in Alphabetical Order/select (output filehandle) ############################################################################ select REPORT1; $^ = 'MyTop'; select REPORT2; $^ = 'MyTop'; -------------- my $oldfh = select STDERR; $| = 1; select $oldfh; -------------- select((select(STDERR), $| = 1)[0]) -------------- use IO::Handle; # note: this is *not* a small module STDOUT->autoflush(1); -------------- use IO::Handle; REPORT1->format_top_name("MyTop"); REPORT2->format_top_name("MyTop"); ################################################################################# 29:Functions/Perl Functions in Alphabetical Order/select (ready file descriptors) ################################################################################# $rin = $win = $ein = ""; vec($rin, fileno(STDIN), 1) = 1; vec($win, fileno(STDOUT), 1) = 1; $ein = $rin | $win; -------------- sub fhbits { my @fhlist = @_; my $bits; for (@fhlist) { vec($bits, fileno($_), 1) = 1; } return $bits; } $rin = fhbits(qw(STDIN TTY MYSOCK)); -------------- ($nfound, $timeleft) = select($rout=$rin, $wout=$win, $eout=$ein, $timeout); -------------- $nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef); -------------- select undef, undef, undef, 4.75; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/semop ####################################################### $semop = pack "s*", $semnum, -1, 0; semop $semid, $semop or die "Semaphore trouble: $!\n"; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/send ###################################################### send SOCK, $buffer, length $buffer ############################################################# 29:Functions/Perl Functions in Alphabetical Order/setpriority ############################################################# setpriority 0, 0, getpriority(0, 0) + 4; ############################################################ 29:Functions/Perl Functions in Alphabetical Order/setsockopt ############################################################ use Socket; socket(SOCK, ...) or die "Can't make socket: $!\n"; setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, 1) or warn "Can't do setsockopt: $!\n"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/shift ####################################################### sub marine { my $fathoms = shift; # depth my $fishies = shift; # number of fish my $o2 = shift; # oxygen concentration # ... } -------------- while (defined($_ = shift)) { /^[^-]/ && do { unshift @ARGV, $_; last }; /^-w/ && do { $WARN = 1; next }; /^-r/ && do { $RECURSE = 1; next }; die "Unknown argument $_\n"; } ########################################################## 29:Functions/Perl Functions in Alphabetical Order/shutdown ########################################################## shutdown(SOCK, 0); # no more reading shutdown(SOCK, 1); # no more writing shutdown(SOCK, 2); # no more I/O at all -------------- print SERVER "my request\n"; # send some data shutdown(SERVER, 1); # send eof; no more writing $answer = ; # but you can still read ##################################################### 29:Functions/Perl Functions in Alphabetical Order/sin ##################################################### sub asin { atan2($_[0], sqrt(1 - $_[0] * $_[0])) } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/socket ######################################################## use Socket; ############################################################ 29:Functions/Perl Functions in Alphabetical Order/socketpair ############################################################ use Socket; socketpair(Rdr, Wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC); shutdown(Rdr, 1); # no more writing for reader shutdown(Wtr, 0); # no more reading for writer ###################################################### 29:Functions/Perl Functions in Alphabetical Order/sort ###################################################### sub numerically { $a <=> $b } @sortedbynumber = sort numerically 53,29,11,32,7; -------------- @descending = reverse sort numerically 53,29,11,32,7; sub reverse_numerically { $b <=> $a } @descending = sort reverse_numerically 53,29,11,32,7; -------------- @unsorted = qw/sparrow Ostrich LARK catbird blueJAY/; @sorted = sort { lc($a) cmp lc($b) } @unsorted; -------------- # sort from highest to lowerst department sales sub bysales { $sales_amount{$b} <=> $sales_amount{$a} } for $dept (sort bysales keys %sale_amount) { print "$dept => $sales_amount{$dept}\n"; } -------------- sub by_sales_then_dept { $sales_amount{$b} <=> $sales_amount{$a} || $a cmp $b } for $dept (sort by_sales_then_dept keys %sale_amount) { print "$dept => $sales_amount{$dept}\n"; } -------------- sub prospects { $b->{SALARY} <=> $a->{SALARY} || $b->{HEIGHT} <=> $a->{HEIGHT} || $a->{AGE} <=> $b->{AGE} || $a->{LASTNAME} cmp $b->{LASTNAME} || $a->{FIRSTNAME} cmp $b->{FIRSTNAME} } @sorted = sort prospects @recs; -------------- @sorted_lines = sort { @a_fields = split /:/, $a; # colon-separated fields @b_fields = split /:/, $b; $a_fields[3] <=> $b_fields[3] # numeric sort on 4th field, then || $a_fields[0] cmp $b_fields[0] # string sort on 1st field, then || $b_fields[2] <=> $a_fields[2] # reverse numeric sort on 3rd field || ... # etc. } @lines; -------------- @temp = map { [$_, split /:/] } @lines; -------------- @temp = sort { @a_fields = @$a[1..$#$a]; @b_fields = @$b[1..$#$b]; $a_fields[3] <=> $b_fields[3] # numeric sort on 4th field, then || $a_fields[0] cmp $b_fields[0] # string sort on 1st field, then || $b_fields[2] <=> $a_fields[2] # reverse numeric sort on 3rd field || ... # etc. } @temp; -------------- @sorted_lines = map { $_->[0] } @temp; -------------- @sorted_lines = map { $_->[0] } sort { @a_fields = @$a[1..$#$a]; @b_fields = @$b[1..$#$b]; $a_fields[3] <=> $b_fields[3] || $a_fields[0] cmp $b_fields[0] || $b_fields[2] <=> $a_fields[2] || ... } map { [$_, split /:/] } @lines; -------------- sub numerically ($$) { my ($a, $b) = @_; $a <=> $b; } -------------- sub numerically ($a, $b) { $a <=> $b } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/splice ######################################################## sub list_eq { # compare two list values my @a = splice(@_, 0, shift); my @b = splice(@_, 0, shift); return 0 unless @a == @b; # same len? while (@a) { return 0 if pop(@a) ne pop(@b); } return 1; } if (list_eq($len, @foo[1..$len], scalar(@bar), @bar)) { ... } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/split ####################################################### @chars = split //, $word; @fields = split /:/, $line; @words = split " ", $paragraph; @lines = split /^/, $buffer; -------------- print join ':', split / */, 'hi there'; -------------- ($login, $passwd, $remainder) = split /:/, $_, 3; -------------- split /([-,])/, "1-10,20"; -------------- (1, '-', 10, ',', 20) -------------- split /(-)|(,)/, "1-10,20"; -------------- (1, '-', undef, 10, undef, ',', 20) -------------- $string = join(' ', split(' ', $string)); -------------- $header =~ s/\n\s+/ /g; # Merge continuation lines. %head = ('FRONTSTUFF', split /^(\S*?):\s*/m, $header); -------------- open PASSWD, '/etc/passwd'; while () { chomp; # remove trailing newline ($login, $passwd, $uid, $gid, $gcos, $home, $shell) = split /:/; ... } -------------- while (<>) { foreach $word (split) { $count{$word}++; } } ######################################################### 29:Functions/Perl Functions in Alphabetical Order/sprintf ######################################################### sprintf "version is v%vd\n", $^V; # Perl's version sprintf "address is %vd\n", $addr; # IPv4 address sprintf "address is %*vX\n", ":", $addr; # IPv6 address sprintf "bits are %*vb\n", " ", $bits; # random bitstrings ###################################################### 29:Functions/Perl Functions in Alphabetical Order/sqrt ###################################################### use Math::Complex; print sqrt(-2); # prints 1.4142135623731i ####################################################### 29:Functions/Perl Functions in Alphabetical Order/srand ####################################################### srand( time() ^ ($$ + ($$ << 15)) ); -------------- srand (time ^ $$ ^ unpack "%32L*", `ps wwaxl | gzip`); ###################################################### 29:Functions/Perl Functions in Alphabetical Order/stat ###################################################### ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size, $atime,$mtime,$ctime,$blksize,$blocks) = stat $filename; -------------- if (-x $file and ($d) = stat(_) and $d < 0) { print "$file is executable NFS file\n"; } -------------- $mode = (stat($filename))[2]; printf "Permissions are %04o\n", $mode & 07777; -------------- use File::stat; $sb = stat($filename); printf "File is %s, size is %s, perm %04o, mtime %s\n", $filename, $sb->size, $sb->mode & 07777, scalar localtime $sb->mtime; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/study ####################################################### while (<>) { study; print ".IX foo\n" if /\bfoo\b/; print ".IX bar\n" if /\bbar\b/; print ".IX blurfl\n" if /\bblurfl\b/; ... print; } -------------- $search = 'while (<>) { study;'; foreach $word (@words) { $search .= "++\$seen{\$ARGV} if /\\b$word\\b/i;\n"; } $search .= "}"; @ARGV = @files; undef $/; # slurp each entire file eval $search; # this screams die $@ if $@; # in case eval failed $/ = "\n"; # restore normal input terminator foreach $file (sort keys(%seen)) { print "$file\n"; } -------------- @pats = (); foreach $word (@words) { push @pats, qr/\b${word}\b/i; } @ARGV = @files; undef $/; # slurp each entire file while (<>) { for $pat (@pats) { $seen{$ARGV}++ if /$pat/; } } $/ = "\n"; # restore normal input terminator foreach $file (sort keys(%seen)) { print "$file\n"; } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/sub ##################################################### sub numstrcmp ($$) : locked { my ($a, $b) = @_; return $a <=> $b || $a cmp $b; } ######################################################## 29:Functions/Perl Functions in Alphabetical Order/substr ######################################################## substr($var, 0, 0) = "Larry"; -------------- substr($var, 0, 1) = "Moe"; -------------- substr($var, -1) = "Curly"; -------------- $oldstr = substr($var, -1, 1, "Curly"); -------------- substr($var, -10) =~ s/ /./g; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/symlink ######################################################### $can_symlink = eval { symlink("",""); 1 }; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/syscall ######################################################### sub finetime() { package main; # for next require require 'syscall.ph'; # presize buffer to two 32-bit longs... my $tv = pack("LL", ()); syscall(&SYS_gettimeofday, $tv, undef) >= 0 or die "gettimeofday: $!"; my($seconds, $microseconds) = unpack("LL", $tv); return $seconds + ($microseconds / 1_000_000); } -------------- require 'syscall.ph'; syscall(&SYS_setgroups, scalar @newgids, pack("i*", @newgids)) or die "setgroups: $!"; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/sysopen ######################################################### open(FH, "<", $path); sysopen(FH, $path, O_RDONLY); -------------- open(FH, ">", $path); sysopen(FH, $path, O_WRONLY | O_TRUNC | O_CREAT); -------------- open(FH, ">>", $path); sysopen(FH, $path, O_WRONLY | O_APPEND | O_CREAT); -------------- open(FH, "+<", $path); sysopen(FH, $path, O_RDWR); -------------- sysopen(FH, $path, O_WRONLY | O_EXCL | O_CREAT); -------------- sysopen(FH, $path, O_WRONLY | O_APPEND); -------------- sysopen(FH, $path, O_RDWR | O_CREAT); -------------- sysopen(FH, $path, O_RDWR | O_EXCL | O_CREAT); -------------- sysopen(FH, $path, O_WRONLY | O_NONBLOCK); ######################################################## 29:Functions/Perl Functions in Alphabetical Order/system ######################################################## @args = ("command", "arg1", "arg2"); system(@args) == 0 or die "system @args failed: $?" -------------- $exit_value = $? >> 8; $signal_num = $? & 127; # or 0x7f, or 0177, or 0b0111_1111 $dumped_core = $? & 128; # or 0x80, or 0200, or 0b1000_0000 ########################################################## 29:Functions/Perl Functions in Alphabetical Order/syswrite ########################################################## use Errno qw/EINTR/; $blksize = (stat FROM)[11] || 16384; # preferred block size? while ($len = sysread FROM, $buf, $blksize) { if (!defined $len) { next if $! == EINTR; die "System read error: $!\n"; } $offset = 0; while ($len) { # Handle partial writes. $written = syswrite TO, $buf, $len, $offset; die "System write error: $!\n" unless defined $written; $offset += $written; $len -= $written; } } ##################################################### 29:Functions/Perl Functions in Alphabetical Order/tie ##################################################### use NDBM_File; tie %ALIASES, "NDBM_File", "/etc/aliases", 1, 0 or die "Can't open aliases: $!\n"; while (($key,$val) = each %ALIASES) { print $key, ' = ', $val, "\n"; } untie %ALIASES; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/tied ###################################################### ref tied %hash ###################################################### 29:Functions/Perl Functions in Alphabetical Order/time ###################################################### $start = time(); system("some slow command"); $end = time(); if ($end - $start > 1) { print "Program started: ", scalar localtime($start), "\n"; print "Program ended: ", scalar localtime($end), "\n"; } ####################################################### 29:Functions/Perl Functions in Alphabetical Order/times ####################################################### ($user, $system, $cuser, $csystem) = times(); printf "This pid and its kids have consumed %.3f seconds\n", $user + $system + $cuser + $csystem; -------------- $start = times(); ... $end = times(); printf "that took %.2f CPU seconds of user time\n", $end - $start; ######################################################### 29:Functions/Perl Functions in Alphabetical Order/ucfirst ######################################################### ucfirst lc $word ####################################################### 29:Functions/Perl Functions in Alphabetical Order/umask ####################################################### umask((umask() & 077) | 7); # don't change the group bits ####################################################### 29:Functions/Perl Functions in Alphabetical Order/undef ####################################################### undef $foo; undef $bar{'blurfl'}; # Different from delete $bar{'blurfl'}; undef @ary; undef %hash; undef &mysub; undef *xyz; # destroys $xyz, @xyz, %xyz, &xyz, etc. -------------- select(undef, undef, undef, $naptime); return (wantarray ? () : undef) if $they_blew_it; return if $they_blew_it; # (same thing) -------------- ($a, $b, undef, $c) = &foo; # Ignore third value returned ######################################################## 29:Functions/Perl Functions in Alphabetical Order/unlink ######################################################## $count = unlink 'a', 'b', 'c'; unlink @goners; unlink glob("*.orig"); -------------- #!/usr/bin/perl @cannot = grep {not unlink} @ARGV; die "$0: could not unlink @cannot\n" if @cannot; ######################################################## 29:Functions/Perl Functions in Alphabetical Order/unpack ######################################################## while (<>) { ($year, $title, $author) = unpack("A4 x A23 A*", $_); print "$author won ${year}'s Hugo for $title.\n"; } -------------- #!/usr/bin/perl $_ = <> until ($mode,$file) = /^begin\s*(\d*)\s*(\S*)/; open(OUT,"> $file") if $file ne ""; while (<>) { last if /^end/; next if /[a-z]/; next unless int((((ord() - 32) & 077) + 2) / 3) == int(length() / 4); print OUT unpack "u", $_; } chmod oct($mode), $file; -------------- undef $/; $checksum = unpack ("%32C*", <>) % 65535; -------------- $setbits = unpack "%32b*", $selectmask; -------------- while (<>) { tr#A-Za-z0-9+/##cd; # remove non-base64 chars tr#A-Za-z0-9+/# -_#; # convert to uuencoded format $len = pack("c", 32 + 0.75*length); # compute length byte print unpack("u", $len . $_); # uudecode and print } ######################################################### 29:Functions/Perl Functions in Alphabetical Order/unshift ######################################################### unshift @ARGV, '-e', $cmd unless $ARGV[0] =~ /^-/; ##################################################### 29:Functions/Perl Functions in Alphabetical Order/use ##################################################### use 5.005_03; -------------- use 5.6.0; # That's version 5, subversion 6, patchlevel 0. -------------- use autouse 'Carp' => qw(carp croak); use bytes; use constant PI => 4 * atan2(1,1); use diagnostics; use integer; use lib '/opt/projects/spectre/lib'; use locale; use sigtrap qw(die INT QUIT); use strict qw(subs vars refs); use warnings "deprecated"; -------------- no integer; no strict 'refs'; no utf8; no warnings "unsafe"; ####################################################### 29:Functions/Perl Functions in Alphabetical Order/utime ####################################################### #!/usr/bin/perl # montouch - post-date files now + 1 month $day = 24 * 60 * 60; # 24 hours of seconds $later = time() + 30 * $day; # 30 days is about a month utime $later, $later, @ARGV; -------------- #!/usr/bin/perl # montouch - post-date files now + 1 month $later = time() + 30 * 24 * 60 * 60; @cannot = grep {not utime $later, $later, $_} @ARGV; die "$0: Could not touch @cannot.\n" if @cannot; ######################################################## 29:Functions/Perl Functions in Alphabetical Order/values ######################################################## for (@hash{keys %hash}) { s/foo/bar/g } # old way for (values %hash) { s/foo/bar/g } # now changes values ##################################################### 29:Functions/Perl Functions in Alphabetical Order/vec ##################################################### $bitstring = ""; $offset = 0; foreach $num (0, 5, 5, 6, 2, 7, 12, 6) { vec($bitstring, $offset++, 4) = $num; } -------------- $num_elements = length($bitstring)*2; # 2 elements per byte foreach $offset (0 .. $num_elements-1) { print vec($bitstring, $offset, 4), "\n"; } -------------- @bits = (0,0,1,0, 1,0,1,0, 1,1,0,0, 0,0,1,0); $bitstring = ""; $offset = 0; foreach $bit (@bits) { vec($bitstring, $offset++, 1) = $bit; } print "$bitstring\n"; # "TC", ie. '0x54', '0x43' -------------- $bitstring = pack "b*", join('', @bits); print "$bitstring\n"; # "TC", same as before -------------- @bits = split(//, unpack("b*", $bitstring)); print "@bits\n"; # 0 0 1 0 1 0 1 0 1 1 0 0 0 0 1 0 ######################################################### 29:Functions/Perl Functions in Alphabetical Order/waitpid ######################################################### use POSIX ":sys_wait_h"; do { $kid = waitpid(-1,&WNOHANG); } until $kid == -1; ########################################################### 29:Functions/Perl Functions in Alphabetical Order/wantarray ########################################################### return unless defined wantarray; # don't bother doing more my @a = complex_calculation(); return wantarray ? @a : \@a; ###################################################### 29:Functions/Perl Functions in Alphabetical Order/warn ###################################################### warn "Debug enabled" if $debug; -------------- warn "Something wicked\n" if $^W; -------------- local $SIG{__WARN__} = sub { my $msg = shift; die $msg if $msg =~ /isn't numeric/; }; -------------- # wipe out *all* compile-time warnings BEGIN { $SIG{__WARN__} = sub { warn $_[0] if $DOWARN } } my $foo = 10; my $foo = 20; # no warning about duplicate my $foo, # but hey, you asked for it! # no compile-time or run-time warnings before here $DOWARN = 1; # *not* a built-in variable # run-time warnings enabled after here warn "\$foo is alive and $foo!"; # does show up ####################################################### 29:Functions/Perl Functions in Alphabetical Order/write ####################################################### $old_fh = select(HANDLE); $~ = "NEWNAME"; select($old_fh); -------------- use IO::Handle; HANDLE->format_name("NEWNAME"); -------------- $~ = "OtherPack::NEWNAME"; -------------- use IO::Handle; HANDLE->format_top_name("NEWNAME_TOP"); ####################################################### 30:The Standard Perl Library/A Tour of the Perl Library ####################################################### % perl -le "print foreach @INC" /usr/libdata/perl5/sparc-openbsd/5.00503 /usr/local/libdata/perl5/sparc-openbsd/5.00503 /usr/libdata/perl5 /usr/local/libdata/perl5 /usr/local/libdata/perl5/site_perl/sparc-openbsd /usr/libdata/perl5/site_perl/sparc-openbsd /usr/local/libdata/perl5/site_perl /usr/libdata/perl5/site_perl . #################### 31:Pragmatic Modules #################### use strict; use integer; { no strict 'refs'; # allow symbolic references no integer; # resume floating point arithmetic # .... } ###################################### 31:Pragmatic Modules/C ###################################### sub afunc : method; my $closure = sub : method { ... }; use attributes; @attrlist = attributes::get(\&afunc); ################################### 31:Pragmatic Modules/C ################################### use autouse 'Carp' => qw(carp croak); carp "this carp was predeclared and autoused"; -------------- use autouse 'Module' => qw(func1 func2($;$) Module::func3); -------------- use Module qw(func1 func2); -------------- use Module; use autouse Module => qw(hue($) cry(&$)); cry "this cry was predeclared and autoused"; ################################ 31:Pragmatic Modules/C ################################ use base qw(Mother Father); -------------- BEGIN { require Mother; require Father; push @ISA, qw(Mother Father); } ##################################### 31:Pragmatic Modules/C ##################################### use charnames ':full'; print "\N{GREEK SMALL LETTER SIGMA} is called sigma.\n"; use charnames ':short'; print "\N{greek:Sigma} is an upper-case sigma.\n"; use charnames qw(cyrillic greek); print "\N{sigma} is Greek sigma, and \N{be} is Cyrillic b.\n"; #################################### 31:Pragmatic Modules/C #################################### use constant BUFFER_SIZE => 4096; use constant ONE_YEAR => 365.2425 * 24 * 60 * 60; use constant PI => 4 * atan2 1, 1; use constant DEBUGGING => 0; use constant ORACLE => 'oracle@cs.indiana.edu'; use constant USERNAME => scalar getpwuid($<); use constant USERINFO => getpwuid($<); sub deg2rad { PI * $_[0] / 180 } print "This line does nothing" unless DEBUGGING; # references can be declared constant use constant CHASH => { foo => 42 }; use constant CARRAY => [ 1,2,3,4 ]; use constant CPSEUDOHASH => [ { foo => 1}, 42 ]; use constant CCODE => sub { "bite $_[0]\n" }; print CHASH->{foo}; print CARRAY->[$i]; print CPSEUDOHASH->{foo}; print CCODE->("me"); print CHASH->[10]; # compile-time error -------------- print "The value of PI is @{[ PI ]}.\n"; -------------- $homedir = USERINFO[7]; # WRONG $homedir = (USERINFO)[7]; # Right -------------- use constant CAMELIDS => (); use constant CAMEL_HOME => undef; ################################################################# 31:Pragmatic Modules/C/Restrictions on use constant ################################################################# use constant FOO => 4, BAR => 5; # WRONG -------------- use constant FOO => 4 use constant BAR => 5; -------------- my $PI : constant = 4 * atan2(1,1); ####################################### 31:Pragmatic Modules/C ####################################### use diagnostics; # compile-time enable use diagnostics -verbose; enable diagnostics; # run-time enable disable diagnostics; # run-time disable -------------- BEGIN { $diagnostics::PRETTY = 1 } use diagnostics; -------------- use diagnostics; print NOWHERE "nothing\n"; print STDERR "\n\tThis message should be unadorned.\n"; warn "\tThis is a user warning"; print "\nDIAGNOSTIC TESTER: Please enter a here: "; my $a, $b = scalar ; print "\n"; print $x/$y; -------------- BEGIN { $diagnostics::DEBUG = 1 } use diagnostics; ################################## 31:Pragmatic Modules/C ################################## package Pet; use strict; use fields qw(name weight _Pet_pid); my $PID = 0; sub new { my Pet $self = shift; unless (ref $self) { $self = fields::new($self); $self->{_Pet_pid} = "this is Pet's secret ID"; } $self->{name} = "Hey, you!"; $self->{weight} = 20; return $self; } 1; -------------- use Pet; my Pet $rock = new Pet; # typed lexical $rock->{name} = "quartz"; $rock->{weight} = "2kg"; $rock->{_Pet_pid} = 1233; # private attribute $rock->{color} = "blue"; # generates compile-time error -------------- package Dog; use strict; use base 'Pet'; # inherit fields and methods from Pet use fields qw(name pedigree); # override Pet name attribute, # add new pedigree attribute use fields qw(baz _Dog_private); # not shared with Pet sub new { my $class = shift; my $self = fields::new($class); $self->SUPER::new(); # init base fields $self->{pedigree} = "none"; # init own fields return $self; } In a separate program, I: use Dog; my Dog $spot = new Dog; # typed lexical $spot->{name} = "Theloneus"; # not inherited $spot->{weight} = "30lbs"; # inherited $spot->{pedigree} = "mutt"; # not inherited $spot->{color} = "brown"; # generates compile time error $spot->{_Pet_pid} = 3324; # generates compile time error -------------- my Pet $var = Pet::->new; $var->{foo} = 42; # this will generate a compile-time error $var->{zap} = 42; -------------- package Critter::Sounds; use fields qw(cat dog bird); sub new { my Critter::Sounds $self = shift; $self = fields::new($self) unless ref $self; $self->{cat} = 'meow'; # scalar element @$self{'dog','bird'} = ('bark','tweet'); # slice return $self; } -------------- sub dogtag { my $tag = fields::phash([qw(name rank ser_num)], [@_]); } -------------- my $tag = fields::phash(name => "Joe", rank => "captain", ser_num => 42); my $pseudohash = fields::phash(%args); #################################### 31:Pragmatic Modules/C #################################### $can_perhaps_read = -r "file"; # use the mode bits { use filetest 'access'; # intuit harder $can_really_read = -r "file"; } $can_perhaps_read = -r "file"; # use the mode bits again ################################### 31:Pragmatic Modules/C ################################### use integer; $x = 10/3; # $x is now 3, not 3.33333333333333333 -------------- use integer; $x = 1.8; $y = $x + 1; $z = -1.8; -------------- % perl -le 'print (4 % -3)' -2 % perl -Minteger -le 'print (4 % -3)' 1 ################################ 31:Pragmatic Modules/C ################################ use less; # These are all UNIMPLEMENTED! use less 'CPU'; use less 'memory'; use less 'time'; use less 'disk'; use less 'fat'; # great with `use locale' ############################### 31:Pragmatic Modules/C ############################### use lib "$ENV{HOME}/libperl"; # add ~/libperl no lib "."; # remove cwd -------------- use FindBin; # where was script installed? use lib $FindBin::Bin; # use that dir for libs, too -------------- use FindBin qw($Bin); use lib "$Bin/../lib"; -------------- # syntax for sh, bash, ksh, or zsh $ PERL5LIB=$HOME/perllib; export PERL5LIB # syntax for csh or tcsh % setenv PERL5LIB ~/perllib -------------- % perl -I ~/perllib program-path args ################################## 31:Pragmatic Modules/C ################################## @x = sort @y; # ASCII sorting order { use locale; @x = sort @y; # Locale-defined sorting order } @x = sort @y; # ASCII sorting order again ################################ 31:Pragmatic Modules/C ################################ use open IN => ":crlf", OUT => ":raw"; -------------- open FH, "<:para :DEFAULT", $file or die "can't open $file: $!"; #################################### 31:Pragmatic Modules/C #################################### package Number; use overload "+" => \&myadd, "-" => \&mysub, "*=" => "multiply_by"; -------------- use Number; $a = new Number 57; $b = $a + 5; ############################## 31:Pragmatic Modules/C ############################## use re 'taint'; # Contents of $match are tainted if $dirty was also tainted. ($match) = ($dirty =~ /^(.*)$/s); # Allow code interpolation: use re 'eval'; $pat = '(?{ $var = 1 })'; # embedded code execution /alpha${pat}omega/; # won't fail unless under -T # and $pat is tainted use re 'debug'; # like "perl -Dr" /^(.*)$/s; # output debugging info during # compile and run time use re 'debugcolor'; # same as 'debug', # but with colored output -------------- $code = '(?{ $n++ })'; # code assertion $str = '\b\w+\b' . $code; # build string to interpolate $line =~ /$str/; # this needs use re 'eval' $pat = qr/$str/; # this also needs use re 'eval' $line =~ /$pat/; # but this doesn't need use re 'eval' ################################### 31:Pragmatic Modules/C ################################### use sigtrap; use sigtrap qw(stack-trace old-interface-signals); # same thing use sigtrap qw(BUS SEGV PIPE ABRT); use sigtrap qw(die INT QUIT); use sigtrap qw(die normal-signals); use sigtrap qw(die untrapped normal-signals); use sigtrap qw(die untrapped normal-signals stack-trace any error-signals); use sigtrap 'handler' => \&my_handler, 'normal-signals'; use sigtrap qw(handler my_handler normal-signals stack-trace error-signals); ################################################################# 31:Pragmatic Modules/C/Other Arguments to C ################################################################# % perl -Msigtrap -le 'print $sigtrap::VERSION' 1.02 ########################################################## 31:Pragmatic Modules/C/Examples of C ########################################################## use sigtrap; -------------- use sigtrap qw(stack-trace old-interface-signals); -------------- use sigtrap qw(BUS SEGV PIPE ABRT); -------------- use sigtrap qw(die INT QUIT); -------------- use sigtrap qw(die normal-signals); -------------- use sigtrap qw(die untrapped normal-signals); -------------- use sigtrap qw(die untrapped normal-signals stack-trace any error-signals); -------------- use sigtrap 'handler' => \&my_handler, 'normal-signals'; -------------- use sigtrap qw(handler my_handler normal-signals stack-trace error-signals); ################################## 31:Pragmatic Modules/C ################################## use strict; # Install all three strictures. use strict "vars"; # Variables must be predeclared. use strict "refs"; # Can't use symbolic references. use strict "subs"; # Bareword strings must be quoted. use strict; # Install all... no strict "vars"; # ...then renege on one. -------------- use strict 'refs'; $ref = \$foo; # Store "real" (hard) reference. print $$ref; # Dereferencing is ok. $ref = "foo"; # Store name of global (package) variable. print $$ref; # WRONG, run-time error under strict refs. -------------- # make a bunch of attribute accessors for my $methname (qw/name rank serno/) { no strict 'refs'; *$methname = sub { $_[0]->{ __PACKAGE__ . $methname }; } -------------- local our $law = "martial"; -------------- our @EXPORT_OK = qw(name rank serno); -------------- use strict 'subs'; $x = whatever; # WRONG: bareword error! $x = whatever(); # This always works, though. sub whatever; # Predeclare function. $x = whatever; # Now it's ok. # These uses are permitted, because the => quotes: %hash = (red => 1, blue => 2, green => 3); $rednum = $hash{red}; # Ok, braces quote here. # But not this one: @coolnums = @hash{blue, green}; # WRONG: bareword error. @coolnums = @hash{"blue", "green"}; # Ok, words now quoted. @coolnums = @hash{qw/blue green/}; # Likewise. ################################ 31:Pragmatic Modules/C ################################ use subs qw/winken blinken nod/; @x = winken 3..10; @x = nod blinken @x -------------- sub winken(@); sub blinken(\@) : locked; sub nod($) : lvalue; ################################ 31:Pragmatic Modules/C ################################ use vars qw($frobbed @munge %seen); -------------- our($frobbed, @munge, %seen); -------------- our $frobbed = "F"; our @munge = "A" .. $frobbed; our %seen = (); #################################### 31:Pragmatic Modules/C #################################### use warnings; # same as importing "all" no warnings; # same as unimporting "all" use warnings::register; if (warnings::enabled()) { warnings::warn("some warning"); } if (warnings::enabled("void")) { warnings::warn("void", "some warning"); } -------------- use warnings qw(void redefine); no warnings qw(io syntax untie); -------------- use warnings "void"; # Only "void" warnings enabled. ... use warnings "io"; # Both "void" and "io" warnings now enabled. ... no warnings "void"; # Only "io" warnings now enabled. -------------- { use warnings FATAL => qw(numeric uninitialized); $x = $y + $z; } ############################# 32:Standard Modules/Benchmark ############################# use Benchmark qw(timethese cmpthese timeit countit timestr); # You can always pass in code a strings: timethese $count, { 'Name1' => '...code1...', 'Name2' => '...code2...', }; # Or as subroutines references: timethese $count, { 'Name1' => sub { ...code1... }, 'Name2' => sub { ...code2... }, }; cmpthese $count, { 'Name1' => '...code1...', 'Name2' => '...code2...', }; $t = timeit $count, '...code...'; print "$count loops of code took:",timestr($t),"\n"; $t = countit $time, '...code...'; $count = $t->iters; print "$count loops of code took:",timestr($t),"\n"; -------------- use Benchmark qw/countit cmpthese/; sub run($) { countit(5, @_) } for $size (2, 200, 20_000) { $s = "." x $len; print "\nDATASIZE = $size\n"; cmpthese { chop2 => run q{ $t = $s; chop $t; chop $t; }, subs => run q{ ($t = $s) =~ s/..\Z//s; }, lsubstr => run q{ $t = $s; substr($t, -2) = ''; }, rsubstr => run q{ $t = substr($s, 0, length($s)-2); }, }; } ####################### 32:Standard Modules/CGI ####################### use CGI qw(:standard); $who = param("Name"); $phone = param("Number"); @picks = param("Choices"); ############################# 32:Standard Modules/CGI::Carp ############################# use CGI::Carp; warn "This is a complaint"; # Stamp it with progname and date. die "But this one is serious"; # But don't cause server 500 errors. use CGI::Carp qw(carpout); # Import this function. open(LOG, ">>/var/tmp/mycgi-log") or die "Can't append to mycgi-log: $!\n"; carpout(*LOG); # Now uses program-specific errlog. use CGI::Carp qw(fatalsToBrowser); die "Fatal error messages are now sent to browser, too"; ################################# 32:Standard Modules/Class::Struct ################################# use Class::Struct; struct Manager => { # Creates a Manager->new() constructor. name => '$', # Now name() method accesses a scalar value. salary => '$', # And so does salary(). started => '$', # And so does started(). }; struct Shoppe => { # Creates a Shoppe->new() constructor. owner => '$', # Now owner() method accesses a scalar. addrs => '@', # And addrs() method accesses an array. stock => '%', # And stock() method accesses a hash. boss => 'Manager', # Initializes with Manager->new(). }; $store = Shoppe->new(); $store->owner('Abdul Alhazred'); $store->addrs(0, 'Miskatonic University'); $store->addrs(1, 'Innsmouth, Mass.'); $store->stock("books", 208); $store->stock("charms", 3); $store->stock("potions", "none"); $store->boss->name('Prof L. P. Haitch'); $store->boss->salary('madness'); $store->boss->started(scalar localtime); ######################## 32:Standard Modules/CPAN ######################## # Get interactive CPAN shell. % perl -MCPAN -e shell # Just ask for upgrade recommendations. % perl -MCPAN -e 'CPAN::Shell->r' # Install the named module in batch mode. % perl -MCPAN -e "install Class::Multimethods" ######################## 32:Standard Modules/Carp ######################## use Carp; croak "We're outta here!"; use Carp qw(:DEFAULT cluck); cluck "This is how we got here!"; ########################## 32:Standard Modules/Config ########################## use Config; if ($Config{cc} =~ /gcc/) { print "This perl was built by GNU C.\n"; } use Config qw(myconfig config_sh config_vars); print myconfig(); # like perl -V without a pattern print config_sh(); # gives absolutely everything config_vars qw/osname osvers archname/; -------------- osname='openbsd'; osvers='2.6'; archname='OpenBSD.sparc-openbsd'; ####################### 32:Standard Modules/Cwd ####################### use Cwd; $dir = getcwd(); # Where am I? use Cwd 'chdir'; chdir "/tmp"; # Updates $ENV{PWD}. use Cwd 'realpath'; print realpath("/usr////spool//mqueue/../"); # prints /var/spool ########################### 32:Standard Modules/DB_File ########################### use DB_File; -------------- tie(%hash, "DB_File", $filename) # Open database. or die "Can't open $filename: $!"; $v = $hash{"key"}; # Retrieve from database. $hash{"key"} = "value"; # Put value into database. untie %hash; -------------- tie(%hash, "DB_File", "mytree", O_RDWR|O_CREAT, 0666, $DB_BTREE) or die "Cannot open file `mytree': $!"; while (($k, $v) = each %hash) { # Do in-order traversal. print "$k => $v\n"; } -------------- tie(@lines, "DB_File", $textfile, O_RDWR|O_CREAT, 0666, $DB_RECNO) or die "Cannot open textfile $textfile: $!"; # Write a few lines to the file, overwriting any old contents. $lines[0] = "first line"; $lines[1] = "second line"; $lines[2] = "third line"; push @lines, "penult", "last"; # Append two lines to the file. $wc = scalar @lines; # Count lines in file. $last = pop @lines; # Delete and retrieve last line. ################################ 32:Standard Modules/Data::Dumper ################################ use Data::Dumper; print Dumper($store); ############################# 32:Standard Modules/Dumpvalue ############################# use Dumpvalue; Dumpvalue->new->dumpValue($store); ########################### 32:Standard Modules/English ########################### use English; # Use awk-style names. $RS = ''; # instead of $/ while (<>) { next if $NR < 10; # instead of $. ... } # Same thing, but even more cobolaciously. $INPUT_RECORD_SEPARATOR = ''; while (<>) { next if $INPUT_LINE_NUMBER < 10; ... } ######################### 32:Standard Modules/Errno ######################### use Errno; unless (open(FH, $pathname)) { if ($!{ENOENT}) { # We don't need an import for this! warn "$pathname does not exist\n"; } else { warn "open failed on `$pathname': $!"; } } use Errno qw(EINTR EIO :POSIX); if ($! == ENOENT) { .... } ############################ 32:Standard Modules/Exporter ############################ package MyModule; use strict; use Exporter; our $VERSION = 1.00; # Or higher... our @ISA = qw(Exporter); our @EXPORT = qw(f1 %h); # Symbols imported by default. our @EXPORT_OK = qw(f2 f3); # Symbols imported only by request. our %EXPORT_TAGS = ( # Mappings for :shortcuts. a => [qw(f1 f2 f3)], b => [qw(f2 %h)], ); # Your code here. 1; -------------- use MyModule; # Import everything in @EXPORT. use MyModule (); # Load module, no imports at all. use MyModule "f1", "f2", "%h"; # Two subs and a variable. use MyModule qw(:DEFAULT f3); # All in @EXPORT + one sub. use MyModule "f4"; # Fatal because f4 not exported. ######################### 32:Standard Modules/Fatal ######################### use Fatal qw(:void open close); # open properly checked, so no exception is raised on failure. if (open(FH, "< /nonesuch") { warn "no /nonesuch: $!"; } # close not properly checked, so failure raises an exception. close FH; ######################### 32:Standard Modules/Fcntl ######################### use Fcntl; # Import standard fcntl.h constants. use Fcntl ":flock"; # Import LOCK_* constants. use Fcntl ":seek"; # Import SEEK_CUR, SEEK_SET, SEEK_END. use Fcntl ":mode"; # Import S_* stat checking constants. use Fcntl ":Fcompat"; # Import F* constants. ################################## 32:Standard Modules/File::Basename ################################## use File::Basename; $fullname = "/usr/local/src/perl-5.6.1.tar.gz"; $file = basename($fullname); # file="perl-5.6.1.tar.gz" $dir = dirname($fullname); # dir="/usr/local/src" ($file,$dir,$ext) = fileparse($fullname, qr/\..*/); # dir="/usr/local/src/" file="perl-5" ext=".6.1.tar.gz" ($file,$dir,$ext) = fileparse($fullname, qr/\.[^.]*/); # dir="/usr/local/src/" file="perl-5.6.1.tar" ext=".gz" ($file,$dir,$ext) = fileparse($fullname, qr/\.\D.*/); # dir="/usr/local/src/" file="perl-5.6.1" ext=".tar.gz" ($file,$dir,$bak) = fileparse("/tmp/file.bak", qr/~+$/, qr/\.(bak|orig|save)/) # dir="/tmp/" file="file" ext=".bak" ($file,$dir,$bak) = fileparse("/tmp/file~", qr/~+$/, qr/\.(bak|orig|save)/) # dir="/tmp/" file="file" ext="~" ################################# 32:Standard Modules/File::Compare ################################# use File::Compare; printf "fileA and fileB are %s.\n", compare("fileA","fileB") ? "different" : "identical"; use File::Compare 'cmp'; sub munge($) { my $line = $_[0]; for ($line) { s/^\s+//; # Trim leading whitespace. s/\s+$//; # Trim trailing whitespace. } return uc($line); } if (not cmp("fileA", "fileB", sub {munge $_[0] eq munge $_[1]} ) { print "fileA and fileB are kinda the same.\n"; } ############################## 32:Standard Modules/File::Copy ############################## use File::Copy; copy("/tmp/fileA", "/tmp/fileA.orig") or die "copy failed: $!"; copy("/etc/motd", *STDOUT) or die "copy failed: $!"; move("/tmp/fileA", "/tmp/fileB") or die "move failed: $!"; use File::Copy qw/cp mv/; # Get normal Unix names. cp "/tmp/fileA", "/tmp/fileA.orig" or die "copy failed: $!"; mv "/tmp/fileA", "/tmp/fileB" or die "move failed: $!"; -------------- system("cp -R -pi /tmp/dir1 /tmp/dir2") == 0 or die "external cp command status was $?"; ############################## 32:Standard Modules/File::Find ############################## use File::Find; # Print out all directories below current one. find sub { print "$File::Find::name\n" if -d }, "."; # Compute total space used by all files in listed directories. @dirs = @ARGV ? @ARGV : ('.'); my $sum = 0; find sub { $sum += -s }, @dirs; print "@dirs contained $sum bytes\n"; # Alter default behavior to go through symlinks # and visit sub-directories first. find { wanted => \&myfunc, follow => 1, bydepth => 1 }, "."; ############################## 32:Standard Modules/File::Glob ############################## use File::Glob ':glob'; # Override glob built-in. @list = <*.[Cchy]>; # Now uses POSIX glob, not csh glob. use File::Glob qw(:glob csh_glob); @sources = &glob("*.{C,c,h,y,pm,xs}", GLOB_CSH); @sources = csh_glob("*.{C,c,h,y,pm,xs}"); # (same thing) use File::Glob ':glob'; # Override glob built-in. # call glob with extra arguments $homedir = &glob('~jrhacker', GLOB_TILDE | GLOB_ERR); if (GLOB_ERROR) { # An error occurred expanding the home directory. } -------------- glob(@_ ? $_[0] : $_, GLOB_BRACE | GLOB_NOMAGIC | GLOB_QUOTE | GLOB_TILDE); ############################## 32:Standard Modules/File::Spec ############################## use File::Spec; # OO style $path = File::Spec->catfile("subdir", "filename"); # 'subdir/filename' on Unix, OS2, or Mac OS X # 'subdir:filename' on (old) Apple Macs # 'subdir\filename' on Microsoft $path = File::Spec->catfile("", "dir1", "dir2", "filename"); # '/dir1/dir2/filename' on Unix, OS2, or Mac OS X # ':dir1:dir2:filename' on (old) Apple Macs # '\dir1\dir2\filename' on Microsoft use File::Spec::Unix; $path = File::Spec::Unix->catfile("subdir", "filename"); # 'subdir/filename' (even when executed on non-Unix systems) use File::Spec::Mac; $path = File::Spec::Mac->catfile("subdir", "filename"); # 'subdir:filename' use File::Spec::Win32; $path = File::Spec::Win32->catfile("subdir", "filename";) # 'subdir\filename' # Use functional interface instead. use File::Spec::Functions; $path = catfile("subdir", "filename"); ############################## 32:Standard Modules/File::stat ############################## use File::stat; $st = stat($file) or die "Can't stat $file: $!"; if ($st->mode & 0111 and $st->nlink > 1)) { print "$file is executable with many links\n"; } use File::stat ":FIELDS"; stat($file) or die "Can't stat $file: $!"; if ($st_mode & 0111 and $st_nlink > 1) ) { print "$file is executable with many links\n"; } @statinfo = CORE::stat($file); # Access overridden built-in. ############################## 32:Standard Modules/FileHandle ############################## use FileHandle; $fh = new FileHandle; if ($fh->open("< file")) { print $line while defined($line = $fh->getline); $fh->close; } $pos = $fh->getpos; # like tell() $fh->setpos($pos); # like seek() ($readfh, $writefh) = FileHandle::pipe(); autoflush STDOUT 1; -------------- $ofh = select(HANDLE); $~ = 'SomeFormat'; $| = 1; select($ofh); -------------- use FileHandle; HANDLE->format_name('SomeFormat'); HANDLE->autoflush(1); -------------- open my $fh, "< somefile" or die "can't open somefile: $!"; -------------- use FileHandle; my $fh = FileHandle->new("< somefile") or die "can't open somefile: $!"; -------------- use FileHandle; STDOUT->formline("^" . ("<" x 72) . "~~\n", $long_text); ########################### 32:Standard Modules/FindBin ########################### use FindBin; # Import nothing. use lib $FindBin::Bin; use FindBin qw($Bin); # Import $Bin. use lib "$Bin/../lib"; ################################ 32:Standard Modules/Getopt::Long ################################ use Getopt::Long; GetOptions("verbose" => \$verbose, "debug" => \$debug, "output=s" => \$output); ############################### 32:Standard Modules/Getopt::Std ############################### use Getopt::Std; -------------- our ($opt_o, $opt_i, $opt_f); getopt('oif'); # -o, -i, and -f all take arguments. # Sets global $opt_o etc variables. getopts('oif:'); # Now -o & -i are boolean; -f takes an arg. # Still sets global $opt_* as side effect. -------------- my %opts; # We'll place results here. getopt('oif', \%opts); # All three still take arguments. getopts('oif:', \%opts); # Now -o and -i are boolean flags # and only -f takes an argument. ############################## 32:Standard Modules/IO::Socket ############################## use IO::Socket; -------------- $socket = new IO::Socket::INET (PeerAddr => $remote_host, PeerPort => $remote_port, Proto => "tcp", Type => SOCK_STREAM) or die "Can't connect to $remote_host:$remote_port : $!\n"; # Or use the simpler single-argument interface. $socket = IO::Socket::INET->new("$remote_host:$remote_port"); # "localhost:80", for example. print $socket "data\n"; $line = <$socket>; -------------- $server = IO::Socket::INET->new(LocalPort => $server_port, Type => SOCK_STREAM, Reuse => 1, Listen => 10 ) # or SOMAXCONN or die "Can't be a TCP server on port $server_port : $!\n"; while ($client = $server->accept()) { # $client is the new connection $request = <$client>; print $client "answer\n"; close $client; } # Make simple TCP connecting function that returns a filehandle # for use in simple client programs. sub tcp_connect { my ($host, $service) = @_; require IO::Socket; return IO::Socket::INET->new(join ":", $host, $service); } my $fh = tcp_connect("localhost", "smtp"); # with scalar local *FH = tcp_connect("localhost", "smtp"); # with handle ############################## 32:Standard Modules/IPC::Open2 ############################## use IPC::Open2; local(*HIS_OUT, *HIS_IN); # Create local handles if needed. $childpid = open2(*HIS_OUT, *HIS_IN, $program, @args) or die "can't open pipe to $program: $!"; print HIS_IN "here's your input\n"; $his_output = ; close(HIS_OUT); close(README); waitpid($childpid, 0); ############################## 32:Standard Modules/IPC::Open3 ############################## use IPC::Open3; local(*HIS_IN, *HIS_OUT, *HIS_ERR); $childpid = open3(*HIS_IN, *HIS_OUT, *HIS_ERR, $cmd, @args); print HIS_IN "stuff\n"; close(HIS_IN); # Give end of file to kid. @outlines = ; # Read till EOF. @errlines = ; # XXX: block potential if massive print "STDOUT:\n", @outlines, "\n"; print "STDERR:\n", @errlines, "\n"; close HIS_OUT; close HIS_ERR; waitpid($childpid, 0); if ($?) { print "That child exited with wait status of $?\n"; } ################################ 32:Standard Modules/Math::BigInt ################################ use Math::BigInt; $i = Math::BigInt->new($string); use Math::BigInt ':constant'; print 2**200; ################################# 32:Standard Modules/Math::Complex ################################# use Math::Complex; $z = Math::Complex->make(5, 6); $z = cplx(5, 6); # same thing, but shorter $t = 4 - 3*i + $z; # do standard complex math print "$t\n"; # prints 9+3i print sqrt(-9), "\n"; # prints 3i ############################## 32:Standard Modules/Math::Trig ############################## use Math::Trig; $x = tan(0.9); $y = acos(3.7); $z = asin(2.4); $halfpi = pi/2; $rad = deg2rad(120); ################################ 32:Standard Modules/Net::hostent ################################ use Socket; use Net::hostent; print inet_ntoa(gethost("www.perl.com")->addr); # prints 208.201.239.50 printf "%vd", gethost("www.perl.com")->addr; # same thing print gethost("127.0.0.1")->name; # prints localhost use Net::hostent ':FIELDS'; if (gethost($name_or_number)) { print "name is $h_name\n"; print "aliases are $h_aliases\n"; print "addrs are ", join ", " => map { inet_ntoa($_) } @h_addr_list; } ######################### 32:Standard Modules/POSIX ######################### use POSIX; # Round floats up or down to nearest integer. $n = ceil($n); # round up $n = floor($n); # round down # Produces "2000-04-01" for today. $datestr = strftime("%Y-%m-%d", localtime); # Produces "Saturday 04/01/00" for same date. $datestr = strftime("%A %D", localtime); # Try new temporary filenames until we get one # that didn't already exist; see also File::Temp # on CPAN, or in v5.6.1 (maybe). do { $name = tmpnam(); } until sysopen(FH, $name, O_CREAT|O_EXCL|O_RDWR, 0666); # Check for whether system has insecure chown giveaway. if (sysconf(_PC_CHOWN_RESTRICTED)) { print "Hurray -- only the superuser may call chown\n"; } # Find current system's uname info. my($kernel, $hostname, $release, $version, $hardware) = uname(); use POSIX ":sys_wait_h"; while (($dead_pid = waitpid(-1, &WNOHANG)) > 0) { # Do something with $dead_pid if you want. } # Become new session/process-group leader (needed to create daemons # unaffected by keyboard signals or exiting login shells). setsid(0) or die "setsid failed: $!"; -------------- #!/usr/bin/perl -w use strict; $| = 1; for (1..4) { my $got; print "gimme: "; $got = getone(); print "--> $got\n"; } exit; BEGIN { use POSIX qw(:termios_h); my ($term, $oterm, $echo, $noecho, $fd_stdin); $fd_stdin = fileno(STDIN); $term = POSIX::Termios->new(); $term->getattr($fd_stdin); $oterm = $term->getlflag(); $echo = ECHO | ECHOK | ICANON; $noecho = $oterm & ~$echo; sub cbreak { $term->setlflag($noecho); $term->setcc(VTIME, 1); $term->setattr($fd_stdin, TCSANOW); } sub cooked { $term->setlflag($oterm); $term->setcc(VTIME, 0); $term->setattr($fd_stdin, TCSANOW); } sub getone { my $key = ""; cbreak(); sysread(STDIN, $key, 1); cooked(); return $key; } } END { cooked() } ######################## 32:Standard Modules/Safe ######################## use Safe; $sandbox = Safe->new(); # anon sandbox $sandbox = Safe->new("PackName"); # in that symbol table # Enable or disable opcodes by group or name. $sandbox->permit(qw(:base_core)); $sandbox->permit_only(qw(:base_core :base_loop :base_mem)); $sandbox->deny("die"); # like do(), but in the sandbox $ok = $sandbox->rdo($filename); # like do(), but in the sandbox $ok = $sandbox->reval($code); # without 'use strict' $ok = $sandbox->reval($code, 1); # with 'use strict' ########################## 32:Standard Modules/Socket ########################## use Socket; $proto = getprotobyname('udp'); socket(SOCK, PF_INET, SOCK_DGRAM, $proto) or die "socket: $!"; $iaddr = gethostbyname('hishost.com'); $port = getservbyname('time', 'udp'); $sin = sockaddr_in($port, $iaddr); send(SOCK, 0, 0, $sin) or die "send: $!"; $proto = getprotobyname('tcp'); socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "socket: $!"; $port = getservbyname('smtp', 'tcp'); $sin = sockaddr_in($port,inet_aton("127.1")); $sin = sockaddr_in(7,inet_aton("localhost")); $sin = sockaddr_in(7,INADDR_LOOPBACK); connect(SOCK,$sin) or die "connect: $!"; ($port, $iaddr) = sockaddr_in(getpeername(SOCK)); $peer_host = gethostbyaddr($iaddr, AF_INET); $peer_addr = inet_ntoa($iaddr); $proto = getprotobyname('tcp'); socket(SOCK, PF_UNIX, SOCK_STREAM, $proto) or die "connect: $!"; unlink('/tmp/usock'); # XXX: intentionally ignore failure $sun = sockaddr_un('/tmp/usock'); connect(SOCK,$sun) or die "connect: $!"; use Socket qw(:DEFAULT :crlf); # Now you can use CR(), LF(), and CRLF() or # $CR, $LF, and $CRLF for line-endings. ########################## 32:Standard Modules/Symbol ########################## use Symbol "delete_package"; delete_package("Foo::Bar"); print "deleted\n" unless exists $Foo::{"Bar::"}; use Symbol "gensym"; $sym1 = getsym(); # Returns new, anonymous typeglob. $sym2 = getsym(); # Yet another new, anonymous typeglob. package Demo; use Symbol "qualify"; $sym = qualify("x"); # "Demo::x" $sym = qualify("x", "Foo"); # "Foo::x" $sym = qualify("Bar::x"); # "Bar::x" $sym = qualify("Bar::x", "Foo"); # "Bar::x" use Symbol "qualify_to_ref"; sub pass_handle(*) { my $fh = qualify_to_ref(shift, caller); ... } # Now you can call pass_handle with FH, "FH", *FH, or \*FH. ################################# 32:Standard Modules/Sys::Hostname ################################# use Sys::Hostname; $hostname = hostname(); ############################### 32:Standard Modules/Sys::Syslog ############################### use Sys::Syslog; # Misses setlogsock. use Sys::Syslog qw(:DEFAULT setlogsock); # Also gets setlogsock. openlog($program, 'cons,pid', 'user'); syslog('info', 'this is another test'); syslog('mail|warning', 'this is a better test: %d', time()); closelog(); syslog('debug', 'this is the last test'); setlogsock('unix'); openlog("$program $$", 'ndelay', 'user'); syslog('info', 'problem was %m'); # %m == $! in syslogese syslog('notice', 'fooprogram: this is really done'); setlogsock("unix"); # "inet" or "unix" openlog("myprogname", $logopt, $facility); syslog($priority, $format, @args); $oldmask = setlogmask($mask_priority); closelog(); ############################# 32:Standard Modules/Term::Cap ############################# use Term::Cap; $ospeed = eval { require POSIX; my $termios = POSIX::Termios->new(); $termios->getattr; $termios->getospeed; } || 9600; $terminal = Term::Cap->Tgetent({ TERM => undef, OSPEED => $ospeed }); $terminal->Tputs('cl', 1, STDOUT); # Clear screen. $terminal->Tgoto('cm', $col, $row, STDOUT); # Position cursor. ############################## 32:Standard Modules/Text::Wrap ############################## use Text::Wrap; # Imports wrap(). @lines = (<<"EO_G&S" =~ /\S.*\S/g); This particularly rapid, unintelligible patter isn't generally heard, and if it is, it doesn't matter. EO_G&S $Text::Wrap::columns = 50; print wrap(" " x 8, " " x 3, @lines), "\n"; -------------- This particularly rapid, unintelligible patter isn't generally heard, and if it is, it doesn't matter. ############################### 32:Standard Modules/Time::Local ############################### use Time::Local; $time = timelocal($sec,$min,$hours,$mday,$mon,$year); $time = timegm($sec,$min,$hours,$mday,$mon,$year); $time = timelocal(50, 45, 3, 18, 0, 73); print "Scalar localtime gives: ", scalar(localtime($time)), "\n"; $time += 28 * 365.2425 * 24 * 60 * 60; print "Twenty-eight years of seconds later, it's now\n\t", scalar(localtime($time)), "\n"; -------------- Scalar localtime gives: Thu Jan 18 03:45:50 1973 Twenty-eight years of seconds later, it's now Wed Jan 17 22:43:26 2001 ################################### 32:Standard Modules/Time::localtime ################################### use Time::localtime; printf "Year is %d\n", localtime->year() + 1900; $now = ctime(); use Time::localtime; use File::stat; $date_string = ctime(stat($file)->mtime); ############################### 32:Standard Modules/User::grent ############################### use User::grent; $gr = getgrgid(0) or die "No group zero"; if ($gr->name eq "wheel" && @{$gr->members} > 1) { print "gid zero name wheel, with other members"; } $gr = getgr($whoever); # Accepts both string or number. use User::grent ':FIELDS'; getgrgid(0) or die "No group zero"; if ($gr_name eq "wheel" && @gr_members > 1) { print "gid zero name wheel, with other members"; } ############################### 32:Standard Modules/User::pwent ############################### use User::pwent; # Default overrides built-ins only. $pw = getpwnam("daemon") or die "No daemon user"; if ($pw->uid == 1 && $pw->dir =~ m#^/(bin|tmp)?$# ) { print "gid 1 on root dir"; } $pw = getpw($whoever); # Accepts both string or number. $real_shell = $pw->shell || '/bin/sh'; for (($fullname, $office, $workphone, $homephone) = split /\s*,\s*/, $pw->gecos) { s/&/ucfirst(lc($pw->name))/ge; } use User::pwent qw(:FIELDS); # Sets globals in current package. getpwnam("daemon") or die "No daemon user"; if ($pw_uid == 1 && $pw_dir =~ m#^/(bin|tmp)?$# ) { print "gid 1 on root dir"; } use User::pwent qw/pw_has/; if (pw_has(qw[gecos expire quota])) { .... } if (pw_has("name uid gid passwd")) { .... } printf "Your struct pwd supports [%s]\n", scalar pw_has(); ###################### 33:Diagnostic Messages ###################### $foo{$bar} $ref->{"susie"}[12] -------------- $foo{$bar} $ref->{"susie"}[12] -------------- @foo[$bar, $baz, $xyzzy] @{$ref->[12]}{"susie", "queue"} -------------- $var = 'myvar'; $sym = mypack::$var; -------------- $var = 'myvar'; $sym = "mypack::$var"; -------------- open FOO || die; -------------- use constant TYPO => 1; if (TYOP) { print "foo" } -------------- $BADREF = 42; process $BADREF 1,2,3; $BADREF->process(1,2,3); -------------- $BADREF = undef; process $BADREF 1,2,3; $BADREF->process(1,2,3); -------------- *foo += 1; -------------- $foo = *foo; $foo += 1; -------------- print q(The character '(' starts a side comment.); -------------- chmod 777, $filename -------------- { no warnings; eval "format NAME =..."; } -------------- if ($foo = 123) -------------- if ($foo == 123) -------------- sub mod { $_[0] = 1 } mod(2); -------------- my $foo, $bar = @_; -------------- my ($foo, $bar) = @_; -------------- @list = qw( a # a comment b # another comment ); -------------- @list = qw( a b ); -------------- @list = ( 'a', # a comment 'b', # another comment ); -------------- qw( a, b, c ); -------------- qw( a b c ); -------------- sub doit { use attrs qw(locked); } -------------- sub doit : locked { ... -------------- open FOO || die; -------------- open(FOO || die); -------------- %hash = { one => 1, two => 2, }; # WRONG %hash = [ qw( an anon array /)]; # WRONG %hash = ( one => 1, two => 2, ); # right %hash = qw( one 1 two 2 ); # also fine -------------- { no warnings; eval "sub name { ... }"; } -------------- $[ = 0; $[ = 1; ... local $[ = 0; local $[ = 1; ... -------------- $one, $two = 1, 2; -------------- ($one, $two) = (1, 2); -------------- $array = (1,2); -------------- $array = [1,2]; -------------- sub outermost { my $a; sub middle { sub { $a } } } -------------- rand + 5; -------------- rand() + 5; -------------- rand(+5); -------------- open(OUT,">$ARGV[0]") or die "Can't write to $ARGV[0]: $!"; while () { print; print OUT; } close OUT; ########### 34:Glossary ########### $gollum = new Pathetic::Creature "Smeagol"; give $gollum "Fisssssh!"; give $gollum "Precious!"; -------------- print STDERR "Awake! Awake! Fear, Fire, Foes! Awake!\n"; -------------- /Oh s.*t./
Fr Jul 30 13:54:24 CEST 2021
patent_button.gif valid-html401.png elektra.jpg fsfe-logo.png valid-css.png vim.gif anybrowser.gif