Tuesday, December 22, 2009

Reentrant perldoc help

Just want to elaborate on a tip that I gave back in March.
I have a somehow standard way of displaying help for my scripts:
I display the POD data using the $0 perl internal variable.
$0 (or $PROGRAM_NAME if you are using the use English; pragma) "contains the name of the file containing the Perl script being executed", to quote the Camel book.

The help section is printed on screen if a script requires a parameter but none has been provided. I used to write it this way for a command line accepting only one parameter:
sub get_help {
system("perldoc $0");
exit;
}
my $arg = $ARGV[0] || &get_help;

However, I recently ran into a slight difficulty.
On Windows, $0 contains the disk letter followed by the complete path and finally the file name. For example:
C:\Users\Damien\Desktop\test coverage\Perl Scripts

Notice the white spaces in the directory names.
When trying to perldoc this particular file name, I would get an error stating that there is no documentation for "C:\Users\Damien\Desktop\test", "coverage\Perl" nor "Scripts".

My first reaction was simply to surround the $0 file name with "" as shown below:
sub get_help {
system("perldoc \"$0\"");
exit;
}
my $arg = $ARGV[0] || &get_help;

[Added Dec. 29th]
However, an enlightened reader pointed me to the best solution:
sub get_help {
system("perldoc", $0);
exit;
}
my $arg = $ARGV[0] || &get_help;

Using the list argument form of the system function avoids relying on the shell to run your command.

6 comments :

  1. You might want to look at Pod::Usage.

    You can then replace your get_help() with pod2usage().

    http://search.cpan.org/~marekr/Pod-Parser-1.38/lib/Pod/Usage.pm

    ReplyDelete
  2. Please don't use system(STRING), it's insecure and (as you found) subject to any number of quoting hassles. Use system(LIST) instead. It Just Works.

    ReplyDelete
  3. Thanks for the comment! I've updated the post to include your insight.

    ReplyDelete
  4. This comment has been removed by a blog administrator.

    ReplyDelete
  5. This comment has been removed by a blog administrator.

    ReplyDelete
  6. Avoid the system call altogether and display documentation in pure Perl. From the Pod:;Usage man page ...

    use Pod::Usage;
    use Getopt::Long;

    ## Parse options
    GetOptions("help", "man", "flag1") || pod2usage(-verbose => 0);
    pod2usage(-verbose => 1) if ($opt_help);
    pod2usage(-verbose => 2) if ($opt_man);

    ReplyDelete