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

Hi guys, ive been working on a script for the last day or so, and ive hit a stumbling block. The script is finished, but i keep getting a syntax error that i just can't find. i havent been perling long so i sorry if this is a bit of a newbie question. This is the code so far
#! /usr/bin/perl -w use diagnostics; use strict; use Getopt::Std; use Crypt::CBC; getopt( 'kio', \%opts ); $cipher = Crypt::CBC->new( -key => '$opts{"k"}', -cipher => 'Skipjack', ); $INFILE = %opts{"i"}; $OUTFILE = %opts{"o"}; open < INFILE or die "can't open $INFILE: $!"; open > OUTFILE or die "can't open $OUTFILE: $!"; read INFILE, $plaintext; $chipertext = $cipher->encrypt($plaintext); print OUTFILE, $chipertext; close OUTFILE; close INFILE; return (0);

Whenever I run the code I get the following error message:
Global symbol "%opts" requires explicit package name at skipjack.pl.td +y line 8. Global symbol "$cipher" requires explicit package name at skipjack.pl. +tdy line 10. Global symbol "$INFILE" requires explicit package name at skipjack.pl. +tdy line 14. Global symbol "%opts" requires explicit package name at skipjack.pl.td +y line 14.syntax error at skipjack.pl.tdy line 14, near "%opts{" Execution of skipjack.pl.tdy aborted due to compilation errors (#1) (F) You've said "use strict vars", which indicates that all variab +les must either be lexically scoped (using "my"), declared beforehand +using "our", or explicitly qualified to say which package the global var +iable is in (using "::"). Uncaught exception from user code: Global symbol "%opts" requires explicit package name at skipja +ck.pl.tdy line 8. Global symbol "$cipher" requires explicit package name at skipjack.pl. +tdy line 10. Global symbol "$INFILE" requires explicit package name at skipjack.pl. +tdy line 14. Global symbol "%opts" requires explicit package name at skipjack.pl.td +y line 14.syntax error at skipjack.pl.tdy line 14, near "%opts{" Execution of skipjack.pl.tdy aborted due to compilation errors.

Could anyone help me out with the error and if they see anything that needs improving or changing, I would greatly appricate it.
Thanks

UPDATE:
After following your instructions, i now have a working script. Thankyou


Morning!

Replies are listed 'Best First'.
Re: Skipjack Encryption
by serf (Chaplain) on Jan 21, 2006 at 11:28 UTC
    That's not "an" error message, that's a whole string of error messages. The best thing you can do is take them one at a time, figure out what is causing them and fix them - they're there to help you :o)

    This warning that Perl gave you said exactly what I thought to tell you first:

    (F) You've said "use strict vars", which indicates that all variables must either be lexically scoped (using "my"), declared beforehand using "our", or explicitly qualified to say which package the global variable is in (using "::").
    So you need to add my where appropriate.

    Next thing, when you are accessing the %opts hash by keyname you use $opts{"i"} not %opts{"i"}

    That's also not a valid way of using open or read. (read the linked pages to find out how - the perldoc pages have good example code which you can copy)

    You will find that the manual page for Crypt::CBC gives you example code of how to read in a file and process it with that module - all you needed to do was take that code and add the functionality for writing it to a file and you'd have had a working program.

    Try something like this:

    #!/usr/bin/perl # # skipjack.pl - Skipjack encrypt a file. # use strict; use warnings; use diagnostics; use Getopt::Std; use Crypt::CBC; my %opts; getopt( 'kio', \%opts ); my ( $key, $infile, $outfile ) = ( $opts{"k"}, $opts{"i"}, $opts{"o"}); die "Usage: $0 -k KEY -i INFILE -o OUTFILE\n" unless($key && $infile && $outfile); my $cipher = Crypt::CBC->new( -key => $key, -cipher => 'Skipjack', ); $cipher->start('encrypting'); open (INFILE, $infile) || die "Can't read '$infile': $!\n"; open (OUTFILE, ">$outfile") || die "Can't write to '$outfile': $!\n"; while (read(INFILE,my $plaintext,1024)) { print OUTFILE $cipher->crypt($plaintext); } print OUTFILE $cipher->finish; close OUTFILE; close INFILE;
    Read the manual pages for the functions you want to use carefully, and also try writing your codes in little chunks at a time and testing each chunk before you add the next bit - e.g. you've used Getopt::Std here to define the variables, but your script still wasn't working.

    The script would have been simpler for you to read and debug if you had started off by hard-coding those variables into the script and forgetting about Getopt until the main functionality of the script was working.

    I have the feeling you threw so much in at once that the torrent of error messages you got back would have phased you - and that's why you came asking for help rather than reading through what it was telling you and figuring out for yourself.

    Please, before you ask more questions, have a good read through perldoc on the function you are trying to use, try it's examples in stand-alone code snippets till you're comfortable with how it works, and if you're still not getting what you're looking for - try googling for more pieces of code where people have used that.

Re: Skipjack Encryption
by tirwhan (Abbot) on Jan 21, 2006 at 11:34 UTC

    There were multiple errors in your code (below a cleaned-up version which will work, though some more improvements could be made). The most common one was the lack of predeclaring variables while running under use strict.

    A few more notes:

    1. When debugging warnings/errors under Perl it is helpful to just go at it one error at a time. For example, in this case find out why you're getting the warning Global symbol "%opts" requires explicit package name (answer: because you need to declare it before use when running under "use strict"), fix that, run the script again and fix the next error that shows up. This method is best because subsequent warnings/errors can be offshoots of the first one and may be fixed with the first change despite looking entirely unrelated.
    2. Congratulations on using "use strict"! This is a good idea and in this case it would eventually have led you to discover that you misspelled $ciphertext as $chipertext twice.(Update: no it wouldn't, since you consistently spelled it the same/wrong way all the time, thanks serf.) Keep on doing that (using strict, not misspelling variable names ;-)
    3. If you feel overwhelmed by the error messages you're getting, take a step back and don't "use diagnostics". diagnostics can be very helpful and is verbose where normal errors are terse, but it can also be a bit too verbose and often it is more helpful to see only what the error is instead of what it may signify. I'm definitely not recommending you should eschew diagnostics altogether, but you should use both approaches when debugging.
    4. use warnings; can also help you identify problems in your code.Update: Doh!You'd already specified "-w". Thanks to wfsp for pointing that out.

    Lastly, just a question out of curiosity, why are you using Skipjack?

    #! /usr/bin/perl -w use diagnostics; use strict; use Getopt::Std; use Crypt::CBC; my %opts; getopt( 'kio', \%opts ); my $cipher = Crypt::CBC->new({ key => $opts{"k"}, cipher => 'Skipjack', }); my $INFILE = $opts{"i"}; my $OUTFILE = $opts{"o"}; open my $in, "<", $INFILE or die "can't open $INFILE: $!"; open my $out, ">", $OUTFILE or die "can't open $OUTFILE: $!"; local $/=undef; my $plaintext = (<$in>); my $ciphertext = $cipher->encrypt($plaintext); print {$out} $ciphertext; close $out; close $in;

    There are ten types of people: those that understand binary and those that don't.
Re: Skipjack Encryption
by wfsp (Abbot) on Jan 21, 2006 at 11:30 UTC
    hi shadowoflinux

    Have a look at strict and the error messages may start to make a little more sense.

    You need to declare your variables.

    One way could be:

    #! /usr/bin/perl -w use diagnostics; use strict; use Getopt::Std; use Crypt::CBC; my %opts; getopt( 'kio', \%opts ); my $cipher = Crypt::CBC->new( -key => '$opts{"k"}', -cipher => 'Skipjack', ); my $INFILE = %opts{"i"}; my $OUTFILE = %opts{"o"}; open < INFILE or die "can't open $INFILE: $!"; open > OUTFILE or die "can't open $OUTFILE: $!"; my $plaintext; read INFILE, $plaintext; my $chipertext = $cipher->encrypt($plaintext); print OUTFILE, $chipertext; close OUTFILE; close INFILE; return (0);

    untested