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

First I will explain how this program works : When a user wants to create a new user, he needs to type his username. Then this loop will check the file users.txt to see if that username already exists. If so, the user has to type a new username. The file users.txt has entries like this :
test:lamda beta:alpha
test = username and lamda = password, seperated by a : However, this loop works perfectly locally. When I try to do this in a client server kind of way, the loop only checks the first 2 lines, and wont continue after that :( The problem lies in this line at the beginning of the entire script:
$/ = "\015\012";
I had to define this to make sure I would accept proper data from $client. However, when the script checks the file it messes up with the spaces and newlines, because of this defined variable. So I thought I could easily alter that variable before it checks the file like this :
$/ = "\012";
And change it back later. Now it only checks the first 2 lines of the users.txt file, and not the others.. :( Iam totally stuck. Can anyone help me? The loop Iam talking about is this :
$/ = "\012"; open (FILE1, "users.txt") || print "Error occured while opening file"; while (<FILE1>) { ($first,$second ) = split /:/; print $first; if ($login eq $first) { print $client "Sorry this username has been taken, try again!\n\r"; &login; }
This is the entire script so far:
#!/bin/perl use IO::Socket; use IO::Select; $/ = "\015\012"; $nconnections_new = 0; $login = ""; $maxconn = SOMAXONN; $local=IO::Socket::INET->new(Proto=>"tcp", LocalPort=>"1234", Listen=> +$maxconn, Reuse=>1) or die "Can't open socket\n"; while ($client = $local->accept) { $client->autoflush(1); &start; sub start { print $client "This is a test BBS!\n\r"; print $client "(C)reate new user (L)ogin"; print $client "\n\r"; my $option=<$client>; chomp $option; $option="\U$option\E"; if ($option eq "C") { print $client "<<<Create new user>>>\n\r"; print $client "Login must be at least 6 characters.\n\r"; &login; } elsif ($option eq "L") { &logon; } else { &start; } sub login { $/ = "\015\012"; print $client "username:"; $login=<$client>; chomp $login; if ($login eq "") { print $client "Must enter a username!\n\r"; &login; } $/ = "\012"; open (FILE1, "users.txt") || print "Error occured while opening file"; while (<FILE1>) { ($first,$second ) = split /:/; print $first; if ($login eq $first) { print $client "Sorry this username has been taken, try again!\n\r"; &login; } $/ = "\015\012"; } close (FILE1); if (length($login) > 7) { print $client "Your username was longer than 6 characters!\n\r"; &login; } $pass = password(); sub password { print $client "Password:"; $password=<$client>; chomp $password; print $client "\n\rRe-enter password:"; $password2=<$client>; chomp $password2; if ($password ne $password2) { print $client "Passwords do not match, try again!"; &password; } return $password; } open (FILE, ">>users.txt") || print "Error occured while opening file" +; print FILE "$login:$pass\n"; close (FILE); print "File written..\n\r"; exit; } } sub logon { print $client "test"; } close $client;

Replies are listed 'Best First'.
Re (tilly) 1: Variable messes up loops.
by tilly (Archbishop) on Sep 24, 2001 at 17:00 UTC
    Please use strict.pm to catch obvious typos and indent your code. For an example of an indentation style you might use you can run your script through perltidy.

    I have found through experience that those two steps help people catch a very large portion of their common mistakes. In the event that you don't catch your error, the effort will make it tremendously easier for me (or anyone else) to read your code and offer more specific suggestions.

Re: Variable messes up loops.
by tommyw (Hermit) on Sep 24, 2001 at 18:22 UTC
    Let's have a look at that subroutine, shall we? I've asked emacs' cperl mode to indent it for us.
    sub login { $/ = "\015\012"; print $client "username:"; $login=<$client>; chomp $login; if ($login eq "") { print $client "Must enter a username!\n\r"; &login; } $/ = "\012"; open (FILE1, "users.txt") || print "Error occured while opening +file"; while (<FILE1>) { ($first,$second ) = split /:/; print $first; if ($login eq $first) { print $client "Sorry this username has been taken, try again +!\n\r"; &login; } $/ = "\015\012"; } close (FILE1); ...

    What this highlights quite clearly, is that you're resetting $/ whilst you're still reading the file. Try moving it to outside the loop.

    In addition, if it doesn't like the value it's found, then it's going to call &login again, while the file is still open. Which means that the file will be reopened, and $/ set inside a recursive call, then closed and reset when that recursive call ends. Not good thing.

    In fact, the logon subroutine doesn't finish until 7 lines from the end of the script, containing the password subroutine on the way. Not good at all

Re: Variable messes up loops.
by tachyon (Chancellor) on Sep 24, 2001 at 19:47 UTC

    If you run perltidy over it you will also notice that the indentation seems odd - it never returns to the left margin. This is because you are one } short which perl notes as this script does not actually compile.

    #!/bin/perl use IO::Socket; use IO::Select; $/ = "\015\012"; $nconnections_new = 0; $login = ""; $maxconn = SOMAXONN; $local = IO::Socket::INET->new( Proto => "tcp", LocalPort => "1234", Listen => $maxconn, Reuse => 1 ) or die "Can't open socket\n"; while ( $client = $local->accept ) { $client->autoflush(1); &start; sub start { print $client "This is a test BBS!\n\r"; print $client "(C)reate new user (L)ogin"; print $client "\n\r"; my $option = <$client>; chomp $option; $option = "\U$option\E"; if ( $option eq "C" ) { print $client "<<<Create new user>>>\n\r"; print $client "Login must be at least 6 characters.\n\r"; &login; } elsif ( $option eq "L" ) { &logon; } else { &start; } sub login { $/ = "\015\012"; print $client "username:"; $login = <$client>; chomp $login; if ( $login eq "" ) { print $client "Must enter a username!\n\r"; &login; } $/ = "\012"; open( FILE1, "users.txt" ) || print "Error occured while opening file"; while (<FILE1>) { ( $first, $second ) = split /:/; print $first; if ( $login eq $first ) { print $client "Sorry this username has been taken, try again!\ +n\r"; &login; } $/ = "\015\012"; } close(FILE1); if ( length($login) > 7 ) { print $client "Your username was longer than 6 charact +ers!\n\r"; &login; } $pass = password(); sub password { print $client "Password:"; $password = <$client>; chomp $password; print $client "\n\rRe-enter password:"; $password2 = <$client>; chomp $password2; if ( $password ne $password2 ) { print $client "Passwords do not match, try again!" +; &password; } return $password; } open( FILE, ">>users.txt" ) || print "Error occured while opening file"; print FILE "$login:$pass\n"; close(FILE); print "File written..\n\r"; exit; } } sub logon { print $client "test"; } close $client;

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Variable messes up loops.
by cricket (Acolyte) on Sep 24, 2001 at 19:28 UTC
    in addition to strict, using warnings will also catch a lot of potential problems.
    #!/bin/perl use strict; use warnings;
    i never leave home without those.

    --cricket

    i am smaller than a grasshopper
Re: Variable messes up loops.
by pike (Monk) on Sep 24, 2001 at 17:53 UTC
    Not sure if that will help, but you might try to localize $/ before changing its value (i. e. say  local $/; and enclose it in a block). BTW., does the script read all lines of the file if you comment out the statements where you set $/?