http://www.perlmonks.org?node_id=11148328

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Greetings A friend, now deceased, wrote a perl variant of the venerable 'cal' program so that I could have a calendar with week numbers AND be able to see some 5 years of calendar easily - - - all at once!! Except now (I only use this gift occasionally) when I tried to execute the program - - - well - - - its barfing! See first the part of the code in question:
foreach my $arg (@ARGV) { if( $arg =~ /^-B(\d+)$/ ) { # months Before $before = $1; } elsif( $arg =~ /^-B$/ ) { $before = shift( @ARGV ); if( $before !~ /^\d+/ ) { die "Bad before argument ($before)\n"; }
and the resultant (when I try to run the program)
/$ /usr/local/bin/cal2.pl -B 4 Uncaught exception from user code: Bad before argument (-B)
This were good in 5.34. I tried looking in the release notes for changes and (well - - - I'm no programmer - - - sorry) I can't spot anything that would be relevant to my issue. TIA

Replies are listed 'Best First'.
Re: hmm - - - something has changed in perl (from 5.34 to 5.36
by choroba (Cardinal) on Nov 23, 2022 at 17:35 UTC
    I'm getting the same error in 5.26. What works is to use -B4 (i.e. no space).

    Why?

    $before = shift @ARGV assigns the first element of @ARGV to $before. The first element is -B, regardless of the Perl version. Also, changing the array you're currently iterating over doesn't seem to be a safe operation.

    How to fix?

    Iterate over the indices rather than elements if you want to peek into surrounding elements.
    my $before; my $arg_index = 0; while ($arg_index < $#ARGV) { my $arg = $ARGV[$arg_index]; if( $arg =~ /^-B(\d+)$/ ) { # months Before $before = $1; } elsif( $arg =~ /^-B$/ ) { $before = $ARGV[++$arg_index]; if( $before !~ /^\d+/ ) { die "Bad before argument ($before)\n"; } } } continue { ++$arg_index; }

    Note that the code doesn't report "Bad before" if there's no space after -B but the value is not a number.

    How to fix properly?

    Use Getopt::Long.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      100% agree with this! And Getopt::Long is extremely easy:

      use 5.026000; use warnings; use Getopt::Long; GetOptions ( "B|before=i" => \my $before, # An integer argument is required ) or die "User-friendly message\n");

      And if you want -B without any argument to default to say 42, all you have to change is

      GetOptions ( "B|before:42" => \my $before, # An integer argument is optional an +d defaults to 42 when -B used without arg ) or die "User-friendly message\n");

      One step further: set a default, and also give a different default for -B without argument

      GetOptions ( "B|before:42" => \(my $before = 2), ) or die "User-friendly message\n");

      In the first two examples $before will have the value undef when the option -B is not given at all. In the last example the default will be 2.


      Enjoy, Have FUN! H.Merijn
Re: hmm - - - something has changed in perl (from 5.34 to 5.36
by Corion (Patriarch) on Nov 23, 2022 at 17:39 UTC

    That code looks very sketchy and I can imagine various command lines where that code fails. Actually, it can only ever have worked for the -B123 case. The -B 123 case can never have worked.

    My suggestion is to invoke the tool with -B123.

Re: hmm - - - something has changed in perl (from 5.34 to 5.36
by tybalt89 (Monsignor) on Nov 23, 2022 at 18:34 UTC

    try replacing the code you showed with

    foreach my $arg (@ARGV) { if( $arg =~ /^-B(\d+)$/ ) { $before = $1; } elsif ( $before eq '-B' ) { $before = $arg; if( $before !~ /^\d+/ ) { die "Bad before argument ($before)\n"; } } elsif ( $arg eq '-B' ) { $before = $arg; } }
Re: hmm - - - something has changed in perl (from 5.34 to 5.36
by o1bigtenor (Initiate) on Nov 23, 2022 at 20:57 UTC
    Thank you to the responders!!!!!!!!!!!!!

    I was able to figure out that my error was the space between the letter (B or A as the case might be) and the number.
    Big smack upside the head for that one!!!!!!!!!!!!!!!

    Interesting code ideas - - - I will be looking into that for a project I think.

    (I am no programmer but one has to start somewhere and using a gift and trying to make it better - - - that would likely have please the friend that did the original work!)