in reply to Re: adding to hash/writing to file errors
in thread adding to hash/writing to file errors

Okay, here is the revised version, now i get this error when it is compiling:
Global symbol "%logins" requires explicit package name at ./maybe.pl line 62. Execution of ./maybe.pl aborted due to compilation errors.
# AGTS-CLI(Andrew's GTK Time System-Command Line version) # Copyright (C) 2008 Andrew Harris # # This program is free software: you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, email andrew2325@gmail.com! # Contributors: Kelly Royal <netdaemon862@gmail.com> #!/usr/bin/perl use strict; use warnings; my $time = localtime; sub verify { my $username = shift; my %logins = ("aharris" => "1234", "kroyal" => "5678"); if (exists $logins{$username}) { login($username, %logins); } else { print "$username does not exist in our database.\n"; } } sub login { my %logins = shift; my $username = shift; print "Enter your password: "; chomp(my $pass = <STDIN>); if ($pass <=> $logins{$username}) { greeting($username); } else { print "Incorrect password!\n"; } } sub greeting { my $username = shift; print "Welcome $username.\n"; print "Current time is $time\n\n\n"; } sub admin { print "Administrative Tools\n"; print "1. Add user\n"; print "2. Remove user\n"; print "Enter selection: "; chomp(my $selection = <STDIN>); if ($selection == "1") { print "Enter new user name: "; chomp(my $newname = <STDIN>); print "Enter password for $newname: "; chomp(my $newpass = <STDIN>); $logins{$newname} = $newpass; print "User added.\n"; } } while (1) { print "Welcome, Main Menu\n"; print "1. Log in\n"; print "2. Log out\n"; print "3. Administration\n"; print "Enter selection: "; my $selection = <STDIN>; if ($selection == "1") { print "Enter your user name to log in: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGINFILE, ">>login.txt"); print MYLOGINFILE "$username:$time\n"; close(MYLOGINFILE); } elsif ($selection == "2") { print "Enter your user name to log out: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGOUTFILE, ">>login.txt"); print MYLOGOUTFILE "$username:$time\n"; close(MYLOGOUTFILE); } elsif ($selection == "3") { admin; } }

When I remove use strict; use warnings;, it runs, but it doesn't add the users/passwords to the hash..

Replies are listed 'Best First'.
Re^3: adding to hash/writing to file errors
by toolic (Bishop) on May 05, 2008 at 14:48 UTC
    use strict; requires that you declare all variables using my in all scopes. The variable $username is used in your "login" sub, but it is not declared there, nor is it declared as a global variable. Since your call to "login" is:
    login($username, %logins);

    I believe you might want:

    sub login { my $username = shift; my %logins = shift;

    You only declare your $time variable in your "greeting" sub, but you use it in the "while" loop.

      Okay, I got rid of the errors it was returning, now the only problem is it won't add users, and only one of the default users works! I haven't a clue as to why it is doing this. Any suggestions would be appreciated.
        One of the quickest ways to debug Perl code is to start placing print statements near where you are having trouble.

        For looking at the contents of array and hash variables, use Data::Dumper;. For example, to inspect values passed into a sub:

        print Dumper(\@_);

        Taking another pass through your code, I see a couple of unusual things:

        my %logins = shift;

        Inside a sub, shift will remove a single element from the @_ array, not an entire hash as you may expect. See for yourself with:

        print Dumper(\%logins);

        You may want to consider passing hashes by reference (see perlreftut).

        Another oddity is:

        if ( $pass <=> $logins{$username} ) {

        What are you trying to accomplish there?

        Another recommendation is to take advantage of your modular approach by testing your individual subs.

Re^3: adding to hash/writing to file errors
by apl (Monsignor) on May 05, 2008 at 15:16 UTC
    first i had use strict; use warnings; in there, but it wouldn't run the script. just gave a warning about line 83. then i removed it to see if it would work without the debugging.
    Did you consider fixing the bug that caused the warning on line 83?

    use warnings; use strict; aren't debugging aids. They help reveal badly constructed Perl. You debug your program after it compiles cleanly.

      There are no more warnings. The only problem I have now is adding users, and it will only log in for one of the default users(aharris). What program should I use to debug it?
      When I run it, I get:
      1. Log in
      2. Log out
      3. Administration
      Enter selection: 1
      Enter your user name to log in: aharris
      Odd number of elements in hash assignment at ./maybe.pl line 23, <STDIN> line 2.
      Odd number of elements in hash assignment at ./maybe.pl line 33, <STDIN> line 2.
      Enter your password: 1234
      Use of uninitialized value $logins{"aharris"} in numeric comparison
      (<=>) at ./maybe.pl line 37, <STDIN> line 3. Welcome aharris.
      Current time is Mon May 5 11:44:51 2008

      ?

        Starting your script like: perl -d scriptname.pl will bring it up in the perl debugger. Read perldebug. You may also want to dump your data structures at opportune moments with Data::Dumper.

        Your code is well formatted and except for the while() loop surrounding a bunch of subroutine definitions ( the subroutine definitions should be outside the execution path ) otherwise the code is very readable. The parameter passing is incorrect however. Subroutine calls like some_sub( %hash ) are usually not correct as perl passes your hash structure as a flat list which then becomes a local copy in the subroutine. What you probably should be doing is passing a reference to the hash. See: perlreftut. This is why your data structure is not getting updated as your routines only modify their local copy of the structure.


        s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}