loopsperlforeachsubroutine

Perl - Using next inside subroutines - Label not found


I have a problem I am hoping someone can shed some light on...

In my program I have two main subroutines containing the bulk of my code, from those subroutines I then call/reference other smaller subroutines that carry out smaller tasks e.g. deletes certain folders, prints something to screen and so on..

Example of my problem (greatly simplified for the purposes of explaining):

use warnings;
use strict;

sub mainprogram {

    my @foldernames = ("hugefolder", "smallfolder", "giganticfolder");

    SKIP:foreach my $folderName (@foldernames) {
             eval {    
                 $SIG{INT} = sub { interrupt() };     #to catch control-C keyboard command
                 my $results = `grep -R hello $folderName`;  #this takes a long time to grep if its a big folder so pressing control-c will allow the user to skip to the next folder/iteration of the foreach loop
             } 

             print "RESULTS: $results\n";

    }

}

sub interrupt {

     print "You pressed control-c, do you want to Quit or Skip this huge folder and go onto greping the next folder?\n";
     chomp ($quitOrSkip = <STDIN>);
     if ($quitOrSkip =~ /quit/) {
         print "You chose to quit\n";
         exit(0);
     } elsif ($quitOrSkip =~ /skip/) {
         print "You chose to skip this folder and go onto the next folder\n";
         next SKIP;   # <-- this is what causes the problem
     }  else {
         print "Bad answer\n";
         exit(0);
     }

} 

The problem I am having

As you can see in the code above if the user presses ctrl+c while the backticks grep command is running on a folder it will then give them the option to quit the program totally or choose to move onto the next folder in the arrayloop and start greping that.

With the code above though you would inevitably get the "Label not found for next SKIP...at line..." error because it obviously cannot find the SKIP label as its in the other subroutine.

Is there a way this could be done or something to the same effect i.e go to the next iteration of the foreach loop even though the "next SKIP" and the "SKIP:foreach" label are in different subroutines.

I am well aware I could combine the two subroutines so the "next SKIP" is in the same block as the "SKIP:foreach" so it would then work, but if a program calls the "interrupt" subroutine lots of times and in many places then this would mean a lot of repetitive code.

I may well be overlooking something very obvious, but your help is much appreciated, thanks


Solution

  • You could move the results printing inside the eval, then die if you don't want to print them.

    foreach my $folderName (@foldernames) {
        eval {    
            local $SIG{INT} = sub { interrupt() };     #to catch control-C keyboard command
            my $results = `grep -R hello $folderName`;  #this takes a long time to grep if its a big folder so pressing control-c will allow the user to skip to the next folder/iteration of the foreach loop
            print "RESULTS: $results\n";
            1;
        } or do {
            # handle the skip if required
        };
    }
    
    sub interrupt {
        ...
        die 'skip';
        ...
    }
    

    Alternatively:

    foreach my $folderName (@foldernames) {
        eval {    
            local $SIG{INT} = sub { interrupt() };     #to catch control-C keyboard command
            my $results = `grep -R hello $folderName`;  #this takes a long time to grep if its a big folder so pressing control-c will allow the user to skip to the next folder/iteration of the foreach loop
            1;
        } or do {
            next; # Interrupted (or something went wrong), don't print the result.
        };
        print "RESULTS: $results\n";
    }
    
    sub interrupt {
        ...
        die 'skip';
        ...
    }