0

I am attempting to create a subroutine that will open and edit a file in place.

I've been able to get the subroutine to run on it's own as a single Perl script, but when it's in the form of a subroutine I can't pass the parameters properly.

I come from a background of VB.Net and Objective-C where subroutines/functions are prototyped.

$FileName is assigned $ARGV[0] upon executing the script.

Here's my function call:

addComment("v-66721", "Open", "!!!FINDING!!! deployment.config does not exist.", $FileName);

Here is my declaration:

sub addComment($$$$);

And here's the subroutine:

sub addComment {
    my $VULN     = $_[0];
    my $Result   = $_[1];
    my $Comment  = $_[2];
    my $FileName = $_[3];

    # Copy the checklist to a new file name.
    my $outputFile = $FileName;
    $outputFile =~ s/\.ckl/_commented\.ckl/;
    copy( $FileName, $outputFile );

    # Create a temporary file to edit.
    my $tempFile = $FileName;
    $tempFile =~ s/\.ckl/\.ckl_temp/;

    open( OLD, "<$outputFile" ) or die "Can't open $outputFile: $!";
    open( NEW, ">$tempFile" )   or die "Can't open $tempFile: $!";

    my $foundVULN = 0;

    while ( <OLD> ) {

        if ( $foundVULN == 0 && $_ =~ /$VULN/ ) {
            $foundVULN = 1;
        }

        if ( $foundVULN == 1 && $_ =~ /Not_Reviewed/ ) {
            s/Not_Reviewed/$Result/;
        }

        if ( $foundVULN == 1 && $_ =~ /COMMENTS/ ) {
            s/<COMMENTS>/<COMMENTS>$Comment/;
            $foundVULN = 0;
        }

        print NEW $_;
    }

    close(OLD);
    close(NEW);

    # Replace the output file contents with what we did in our temp file.
    rename( $tempFile, $outputFile ) or die "Can't rename $tempFile to $outputFile: $!";

    return;
}

I've tried using

my $VULN = shift
my $Result = shift
my $Comment = shift
my $FileName = shift

But that doesn't seem to work.

I've read that I should not use prototyping but it doesn't seem to work whether I do or not.

The error message I'm getting is:

Prototype mismatch: sub main::addComment ($$$$) vs none at ./Jre8_manual.pl line 614.
Borodin
  • 126,100
  • 9
  • 70
  • 144
dutsnekcirf
  • 263
  • 2
  • 11
  • Please tell me where you learned to apply subroutine prototypes like this? – Borodin Aug 15 '16 at 21:30
  • Note that people familiar with Perl would thank you for using `snake_case` for subroutines and lexical variables. It's safest to reserve `CapitalisedNames` for globals. Perl also has a post-fixed conditional, so single-statement `if` blocks are alien. – Borodin Aug 15 '16 at 21:41
  • If there's any chance that `$VULN` may contain punctuation characters then they may need to be escaped within a regular expression – Borodin Aug 15 '16 at 21:45
  • Thanks for your comments Borodin. Being so new to perl I think I was still a bit unclear as to what is meant by prototyping. I'm comfortable with VB where creating a function you provide the parameters and their types within the function declaration. I think I just needed an ELI5 explanation such as the one provided by mob in order to wrap my head around it. I probably do need to adjust my variable format to use snake_case. In this particular case $VULN wouldn't ever have any punctuation but I understand what you mean. – dutsnekcirf Aug 16 '16 at 15:02

1 Answers1

4

Avoid prototypes. Prototypes in Perl don't work the way they do in other languages and the way that new programmers expect.

Prototype mismatch ... means you have defined (or redefined) a method with a different prototype than the original declaration/definition. In this case.

sub addComment ($$$$);
sub addComment { ... }

have two different prototypes (that is, the second declaration has no prototype). To fix, you could make the sub definition use the same prototype

sub addComment ($$$$);
sub addComment ($$$$) { ... }

but in most cases you are better off without the prototype (and then you don't need the predeclaration, either)

# sub addComment ($$$$);  # don't need this
sub addComment { ... }
Community
  • 1
  • 1
mob
  • 117,087
  • 18
  • 149
  • 283