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

Uninitialized values for arrays suddenly appear in early
subs after I created private var in last sub. I am
really trying to be clear! The script searches html files
for terms input by a form. I am trying to add code which
would append the search results HTML to an open ended
block of HTML called top.html The script was working fine until
I added this to the fourth sub at around line 150:
open(FH,"../top.html") || die "couldn't open file $!\n"; my @html=<FH>; close(FH); print @html;
Now I get unitialized values for:
 @pairs = split(/&/, $buffer); at line 34 in the first sub

 @terms = split(/\s+/, $FORM{'terms'}); at line 71 in the third sub

The arrays aren't declared in the variable declarations but this caused
no errors until I added the private variable. BTW the little block of code I
added works fine as a standalone (thanks to mandog)
I suspect this is too vague to be answered but I really hope someone can help!
TIA
jg

Replies are listed 'Best First'.
(Ovid) Re: uninitialized values for arrays suddenly appear
by Ovid (Cardinal) on Sep 07, 2001 at 23:51 UTC

    You're right when you suspect that this is too vague to be answered. You show us the lines where you get the unitialized values ($buffer and %FORM), but you don't show us the context of those lines or how the values get assigned.

    The lines that you do list appear to be from a hand-rolled alternative to CGI.pm. I could be wrong about that, but I've seen them soooooo many times. Both lines have bugs in them irrespective of the unitiliazed value. The @pairs line ignores that some user agents use a semi-colon to delimit name/value pairs and this is expected to be the standard in the future. The %FORM line suggests that you are using whitespace to delimit multiple form values with the same name. Of course, if one of the form values has embedded whitespace, you can't tell how many values there were supposed to be.

    In other words, use CGI or die; -- no offense. If you show us a bit more of your code, we can show you how to convert it to CGI.pm.

    Cheers,
    Ovid

    Vote for paco!

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: uninitialized values for arrays suddenly appear
by dragonchild (Archbishop) on Sep 07, 2001 at 23:51 UTC
    1. If you aren't already doing so, use strict and warnings.
    2. Post your code. If it's > 200 lines, try and strip out stuff you're positive won't affect anything. If you're not absolutely positive, but only 99.9999% positive, leave it in.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      OK here's the lot of it. Sorry if it is too big.
      Thx for looking at it!
      jg
      #!/usr/local/bin/perl -w # Define Variables # $basedir = '/home/mysite/www/'; $baseurl = 'http://www.mysite.com/'; @files = ('*.htm','*.html','*/*.html'); $title = "The Silver Machine"; $title_url = 'http://mysite.com/'; $search_url = 'http://www.mysite.com/search.html'; # Done # ###################################################################### +######## # Parse Form Search Information &parse_form; # Get Files To Search Through &get_files; # Search the files &search; # Print Results of Search &return_html; sub parse_form { # Get the input read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); # Split the name-value pairs @pairs = split(/&/, $buffer); foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $FORM{$name} = $value; } } sub get_files { chdir($basedir); foreach $file (@files) { $ls = `ls $file`; @ls = split(/\s+/,$ls); foreach $temp_file (@ls) { if (-d $file) { $filename = "$file$temp_file"; if (-T $filename) { push(@FILES,$filename); } } elsif (-T $temp_file) { push(@FILES,$temp_file); } } } } sub search { @terms = split(/\s+/, $FORM{'terms'}); foreach $FILE (@FILES) { open(FILE,"$FILE"); @LINES = <FILE>; close(FILE); $string = join(' ',@LINES); $string =~ s/\n//g; if ($FORM{'boolean'} eq 'AND') { foreach $term (@terms) { if ($FORM{'case'} eq 'Insensitive') { if (!($string =~ /$term/i)) { $include{$FILE} = 'no'; last; } else { $include{$FILE} = 'yes'; } } elsif ($FORM{'case'} eq 'Sensitive') { if (!($string =~ /$term/)) { $include{$FILE} = 'no'; last; } else { $include{$FILE} = 'yes'; } } } } elsif ($FORM{'boolean'} eq 'OR') { foreach $term (@terms) { if ($FORM{'case'} eq 'Insensitive') { if ($string =~ /$term/i) { $include{$FILE} = 'yes'; last; } else { $include{$FILE} = 'no'; } } elsif ($FORM{'case'} eq 'Sensitive') { if ($string =~ /$term/) { $include{$FILE} = 'yes'; last; } else { $include{$FILE} = 'no'; } } } } if ($string =~ /<title>(.*)<\/title>/i) { $titles{$FILE} = "$1"; } else { $titles{$FILE} = "$FILE"; } } } sub return_html { open(FH,"../top.html") || die "couldn't open file $!\n"; my @html=<FH>; close(FH); print @html; print "\n <center>\n <h1>Search Results</h1>\n </center>\n"; print "Here ya go, they're in no particular order:<p><hr size=7 wid +th=75%><p>\n"; print "<ul>\n"; foreach $key (keys %include) { if ($include{$key} eq 'yes') { print "<li class=bullets><span class=bullets><a href=\"$baseu +rl$key\">$titles{$key}</a></span></li>\n"; } } print "</ul>\n"; print "\n"; print "</ul><br><hr size=7 width=75%><P>\n"; print "<ul>\n<li class=bullets><span class=bullets><a href=\"$searc +h_url\">Back to Search Page</a></span></li>\n"; print "<li class=bullets><span class=bullets><a href=\"$title_url\" +>$title</a></span></li>\n"; print "</ul>\n"; print "<hr size=7 width=75%>\n"; print "</body>\n</html>\n"; }

        The following is a quick and dirty reworking of your code to make it parse under strict and it also uses CGI.pm. It's not guaranteed to work, but if you can cobble it together, it's going to be much easier to maintain. In addition to the 'use CGI or die' post that was mentioned, you might want to read 'use strict' is not Perl to gain insight as to why I eliminated (most) of your global variables.

        #!/usr/local/bin/perl -w # Define Variables # use strict; use CGI qw/:standard/; my $basedir = '/home/mysite/www/'; my $baseurl = 'http://www.mysite.com/'; my @files = ('*.htm','*.html','*/*.html'); my $title = "The Silver Machine"; my $title_url = 'http://mysite.com/'; my $search_url = 'http://www.mysite.com/search.html'; # Done # ###################################################################### +######## # Parse Form Search Information # if it's a single form value, map the value as a scalar, other wise, +the value is # and arrayref my %FORM = map { $_, @{[ param($_) ]} > 1 ? [ param($_) ] : param($_) +} param(); # Get Files To Search Through my $files = &get_files; # Search the files my ( $include, $titles ) = search( $files ); # Print Results of Search return_html( $include, $titles ); sub get_files { my @FILES; chdir($basedir); foreach my $file (@files) { my $ls = `ls $file`; my @ls = split(/\s+/,$ls); foreach my $temp_file (@ls) { if (-d $file) { my $filename = "$file$temp_file"; if (-T $filename) { push(@FILES,$filename); } } elsif (-T $temp_file) { push(@FILES,$temp_file); } } } return \@FILES; } sub search { my @FILES = @{$_[0]}; my ( %include, %titles ); my @terms = split(/\s+/, $FORM{'terms'}); foreach my $FILE (@FILES) { my $string; open(FILE,"$FILE") or die "Can't open $FILE for reading: $!"; { local $/; $string = <FILE>; } close(FILE); $string =~ s/\n//g; if ($FORM{'boolean'} eq 'AND') { foreach my $term (@terms) { if ($FORM{'case'} eq 'Insensitive') { if (!($string =~ /$term/i)) { $include{$FILE} = 'no'; last; } else { $include{$FILE} = 'yes'; } } elsif ($FORM{'case'} eq 'Sensitive') { if (!($string =~ /$term/)) { $include{$FILE} = 'no'; last; } else { $include{$FILE} = 'yes'; } } } } elsif ($FORM{'boolean'} eq 'OR') { foreach my $term (@terms) { if ($FORM{'case'} eq 'Insensitive') { if ($string =~ /$term/i) { $include{$FILE} = 'yes'; last; } else { $include{$FILE} = 'no'; } } elsif ($FORM{'case'} eq 'Sensitive') { if ($string =~ /$term/) { $include{$FILE} = 'yes'; last; } else { $include{$FILE} = 'no'; } } } } if ($string =~ /<title>(.*?)<\/title>/i) { $titles{$FILE} = "$1"; } else { $titles{$FILE} = "$FILE"; } } return ( \%include, \%titles ); } sub return_html { my %include = %{$_[0]}; my %titles = %{$_[1]}; open(FH,"../top.html") || die "couldn't open file $!\n"; my @html=<FH>; close(FH); print @html; print "\n <center>\n <h1>Search Results</h1>\n </center>\n"; print "Here ya go, they're in no particular order:<p><hr size=7 wid +th=75%><p>\n"; print "<ul>\n"; foreach my $key (keys %include) { if ($include{$key} eq 'yes') { print "<li class=bullets><span class=bullets><a href=\"$baseu +rl$key\">$titles{$key}</a></span></li>\n"; } } print "</ul>\n"; print "\n"; print "</ul><br><hr size=7 width=75%><P>\n"; print "<ul>\n<li class=bullets><span class=bullets><a href=\"$searc +h_url\">Back to Search Page</a></span></li>\n"; print "<li class=bullets><span class=bullets><a href=\"$title_url\" +>$title</a></span></li>\n"; print "</ul>\n"; print "<hr size=7 width=75%>\n"; print "</body>\n</html>\n"; }

        Cheers,
        Ovid

        Vote for paco!

        Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        To reiterate what Ovid said: use CGI or die;.
        Don't use '$ENV{CONTENT_LENGTH}' and read and split to get your parameters.
        Do use the CGI param function (or method).
        Do use strict;
        1. Add use strict; to the top of your script, under the shebang line.
        2. Fix the errors that pop up.
        3. Fix the logic that depends on those errors.
        4. Come back to us if the error you originally posted about is still there..

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.