Overview

This document serves as a guideline for the formatting of Perl code for use within the IEPM department. The use of consistent formatting and helpful documentation of code will ease development, faciliate debugging and enable collaboration of code.
Due to the numerous styles by which people code and formatting text, it is currently recommended that the lead author (or designated maintainer) of the code in question specified the desired code style for that perl script/module only.

This is a temporary solution from which we as a group must determine the best practise code styles from which we can base future decisions on code formatting which will be suitable for us as a group. In time, we expect to learn from each others code styles to learn the benefits and disadvantages of each and therefore evolve to a standard code style.

Code which will be distributed to others not of our group, should be formatted under the recommended perl formatting specifications as defined in Perl Style Guide.

Version of Perl to use 

There are two main versions of perl at SLAC. They are invoked by #!/usr/local/bin/perl and #!/usr/bin/per,  #!/usr/localbin/perl is maintained centrally and is sharted by AFS. It is the most up to date with all the appropriate shared libraries. #!/usr/bin/perl is a local copy on each host. It is typically an older version of perl and does not always (depends on host) contain all the shared libraries (e.g. the RRD or mysql libraries). We (IEPM group) are committed to to keeping #!/usr/bin/perl reasonably up to date and with the necesssary shared libraries on iepm-bw, iepm-resp and pinger hosts. 

For scripts that will need exporting to other sites use:

#!/usr/bin/perl -w

For  scripts that will only run at SLAC use

#!/usr/local/bin/perl -w

If you are writing CGI scripts then make sure you add the -T taint option. 

Do NOT use #!/bin/env perl -T for CGI scripts, it does not work. 

Writing safe scripts

Run with -w and use strict to ensure Perl isn't assuming things incorrectly. Check all return values. Include the ability to turn on debugging (e.g. print different output depending on the value of my $debug). Use $debug=-1; if you want no output except errors (e.g. for cronjobs), $debug=0 for the default when run from the command line, $debug>0 when trying to debug the program. Larger values of $debug result in more informative output. You can decide whether you are being called from a tty (the command line, NOT a cronjob) by using:

my $debug; #For cronjobs use -1, for normal execution from command line use 0,
                  #for debugging information usr > 0
if (-t STDOUT) {$debug=0;}  #scripot executed from tty (command line)
else               {$debug=-1;} #script executed from cronjob

CGI scripts 

These run as user nobody and need to be super secure. Read the Perl Cookbook and "Writing a Safe Secure CGI program". Always use the taint mode (-T).
When open'ing a file use the three argument form of open (open FILEHANDLE, MODE, LEFT; ) when possible. This will prevent the redirect mode symbol(s) from being misinterpreted as part of the filename. This can be especially important when a user might provide the filename (e.g. in CGI script) and maliciously or unintentionally include a redirct symbol(s) in the filename.

PerlTidy

To ease formatting and translations of the various coding styles available, it is recommended that the tool PerlTidy should be used to (re)format code to the format desired.

The idea is to (re)format code to the desired style for editing and or distribution. However, as suggested above, the code should be formatted to the desired code style of the code maintainer/author.

Usage

PerlTidy is available on all AFS enabled machines at SLAC. The basic syntax is

perltidy [ options ] file1 file2 file3 ...
    perltidy [ options ] file1 -o outfile
    perltidy [ options ] file1 -st >outfile
    perltidy [ options ] outfile

Unless outfile is defined, the (re)formated output is saved to file.tdy. It is possible to overwrite the existing input file with the perltidy output using the -b option.

Installation

In order to utilise the styles defined in this document, the PerlTidy configuration file needs to be added to your home directory. It is suggested that the file is symlinked to support version changes as we redefine the styles as a group.

Run the command:

$ ln -s /afs/slac.stanford.edu/g/scs/net/netmon/perl/.perltidyrc ~/.perltidyrc

Styles

PerlTidy supports user definable profiles that enable easy changing of perl code styles. Three styles are currently in use at SLAC, and they can be applied to existing code using the following commands.

H5. IEPM Style 1

$ perltidy -iepm_style1 file
# simple example perltidy script
my $input = <STDIN>;
if ( open( FILE, "<$input" ) )
  { while ( $file = <FILE> )
      { # pointless loop!
        for ( my $i = 0; $i < 100; $i++ ) { print "."; }
        print "\n";
        push( @entries, $file );    # copy contents of file to memory
        $count++;                   # keep a counter
      }
    close(FILE);
  }
else
  { die "Could not open file $file: $!\n";
  }
IEPM Style 2
$ perltidy -iepm_style2 file
# simple example perltidy script
my $input = <STDIN>;
if (open(FILE, "<$input")) {
  while ($file = <FILE>) {
    # pointless loop!
    for (my $i = 0; $i < 100; $i++) { print "."; }
    print "\n";
    push(@entries, $file);    # copy contents of file to memory
    $count++;                 # keep a counter
  }
  close(FILE);
}
else {
  die "Could not open file $file: $!\n";
}
IEPM Style 3
$ perltidy -iepm_style3 file
# simple example perltidy script
my $input = <STDIN>;
if ( open( FILE, "<$input" ) )
{
    while ( $file = <FILE> )
    {
        # pointless loop!
        for ( my $i = 0; $i < 100; $i++ ) { print "."; }
        print "\n";
        push( @entries, $file );    # copy contents of file to memory
        $count++;                   # keep a counter
    }
    close(FILE);
} ## end if ( open( FILE, "<$input"...
else
{
    die "Could not open file $file: $!\n";
}
Perl Recommended
$ perltidy file
# simple example perltidy script
my $input = <STDIN>;
if ( open( FILE, "<$input" ) ) {
    while ( $file = <FILE> ) {

        # pointless loop!
        for ( my $i = 0 ; $i < 100 ; $i++ ) { print "."; }
        print "\n";
        push( @entries, $file );    # copy contents of file to memory
        $count++;                   # keep a counter
    }
    close(FILE);
}
else {
    die "Could not open file $file: $!\n";
}

Useful hints

Checking IP names and IPv4 addresses

Assume we have the name or IPv4 address in $hostname then one can use (nb the address does not exclude octets of >255).

unless(($hostname=~/(([a-z0-9]+|([a-z0-9]+[-]+[a-z0-9]+))[.])+/)#Name
    || ($hostname=~/ \b(?:\d{1,3}\.){3}\d{1,3}\b/)){            #IPv4 addr
  print "hostname=$hostname, not a valid IP name or address\n";
  exit 101;
}

If one wishes to fully check that the octets are correct (<255) and also get the value of each octet (into $s1..4) then one can use:

\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

If one does not need the values of each octet then a simpler expression will surfice:

NOT-SET

An alternative is to use a library module such as NetAddr::IP.

For IPv6 addresses (which are much more complex) use a module such as: Net::IPv6Addr, Regexp::IPv6,or NetAddr::IP (do a Google search with the name).

Rough template

There is a rough template of a perl script that creates/sets several useful variables (user, host, debug level) uses strict and -w, has USAGE information, ensures created files are accessible to others, processes options, has the disclaimer notice, etc. It is not meant to do anything useful but may be useful as a start.

  • No labels