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

I need help with part of a script I'm writing for an aim bot there is an event called on_im.pl when it receives an instant message it reply to the message fine then it calls addbuddy.pl here is where I get into trouble with the code I have two problems the first one is that it deleted the names in the file then adds the last person to message to the file. The second is I get an error and the script terminates. The error is – undefined subroutine &main:: close called at extras/addbuddy.pl line 31, <FILE> line 1. Here is the code
sub addbuddy { #add victim to buddy list #open names file open (FILE, "names.txt"); $list = <FILE>; close(DATA); #checks each name foreach $item (@list) { #remove lowercase and spaces from names $item =~ s/ //g; $item = lc ($item); } #check if name is in file if ($victim eq "$item") { } else { #if it does not exits add it open (DATA, ">names.txt"); print DATA "$victim\n"; Close (DATA); } #Notify the terminal print "A Buddy name was added.."; } 1;
ok I know there is a problem with the code itself but all so is it a good idea to call the sub or should I just add the code to the event? As you can tell im new to perl and any help would be greatly appreciated thank you..

Replies are listed 'Best First'.
Re: Problem with sub
by davorg (Chancellor) on Dec 29, 2002 at 06:56 UTC
    sub addbuddy { #add victim to buddy list #open names file open (FILE, "names.txt");

    You should always check the value returned by open and take appropriate action. How do you know that the file has been opened successfully?

    $list = <FILE>;

    This takes the first line from FILE and assigns it to $list. That is probably not what you want to do.

    close(DATA); #checks each name foreach $item (@list) {

    You don't have a variable called @list. If you were running your program with use strict turned on then Perl would have told you that.

    #remove lowercase and spaces from names $item =~ s/ //g; $item = lc ($item);

    That doesn't remove lowercase letters from the name. It coverts the name to all lowercase.

    } #check if name is in file if ($victim eq "$item") {

    There's no need to quote $item here.

    } else { #if it does not exits add it open (DATA, ">names.txt");

    Once again, you don't check the return code from open. Also you open the file for writing (which removes all of the data in the file) when you probably want to append the data to the end of the file.

    print DATA "$victim\n"; Close (DATA);

    Perl is case sensitive. That should be close.

    } #Notify the terminal print "A Buddy name was added.."; }

    Hope that helps.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Problem with sub
by pg (Canon) on Dec 29, 2002 at 07:00 UTC
    Here is some code for you, and I have comments along with it.

    Two suggestions:
    1. use strict all the time
    2. always test with -w
    use strict; # do this all the time addbuddy("Peter1"); # the more test cases, the better addbuddy("Peter2"); addbuddy("Peter1"); addbuddy("Peter3"); addbuddy("peTer 1"); sub addbuddy { my $victim = shift; $victim =~ s/ //g; # transform victim in the same way you transfor +m the list, otherwise you may run into trouble without your notice $victim = lc($victim); open(FILE, "<", "names.txt"); # I don't want use +< to confuse you +, even though it is better for this case my @list = <FILE>; #read in the whole list close(FILE); foreach my $item (@list) { chomp($item); #get rid of line breaks $item =~ s/ //g; $item = lc($item); } my %list = map {$_, 1} @list; # the only thing looks tricky in my +code if (!defined($list{$victim})) { open (DATA, ">>names.txt");# you don't want to use >, and over +write your file. print DATA "$victim\n"; close (DATA); print "Buddy $victim was added\n";# always make the debug msg +meaningful } }
      thanks to you all. but it adds the $victim like this to the file net::aim=hash(0x194efc4) instead of botroktester but it will send replies to that name so it is working just want to know why and if that could be changed?

        That's a problem with whatever you're passing into the subroutine. Your subroutine seems to be expecting a string that contains a name, but you're actually passing in a Net::Aim object.

        --
        <http://www.dave.org.uk>

        "The first rule of Perl club is you do not talk about Perl club."
        -- Chip Salzenberg

Re: Problem with sub
by Zaxo (Archbishop) on Dec 29, 2002 at 07:10 UTC

    There are a couple of problems which don't seem to directly relate to your question, but which might be the cause of the difficulty.

    The way you describe it, you seem to be using a bunch of independent standalone scripts which may be subject to scoping problems with variables.

    The code you show has problems with the scope of $victim, an inappropriate comparison in line 019, demolishment of the names.txt file in line 024, an undefined function 'Close', and no result checking in any system interaction.

    A single open with:

    { open my $foo, '+<', $filename or die $!; /$victim/ and last while <$foo>; print $foo $victim, $/ or die $!; }
    is probably a better approach, particularly if file locking is needed.

    After Compline,
    Zaxo