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

Dear monks,

I am trying to create short text user input in my chat client code, and I got stack. I am using a simple do until loop and the loop is breaking after the first run, unless it meets the if condition and re transmitted though the goto function.

Sample of working code provided under:

#!/usr/bin/perl use strict; use warnings; use constant MAXBYTES => scalar 5; my $result; $| = 1; MSG: print "Please be aware maximum length 255 characters!:\n"; do { print "Send this text to clients:\n\n"; chomp ($result = <STDIN>); if (length($result) >= MAXBYTES) { print "\nYou have reached the limit of characters ".length($result +)."!\n\n"; goto MSG; } } until ($result eq "END" or $result "end"); $| = 1;
Update:

Correcting the until condition. Thanks LanX for pointing out my mistake and also about <readmore>.

If the user enters text under the MAXBYTES condition then the loop breaks and exits, even without the user typing end or END

The complete code implementation of TCP chat client is provided under:

#!/usr/bin/perl #TCP Client code use utf8; use strict; use warnings; use Data::Dumper; use IO::Socket::INET; use constant ARGUMENTS => scalar 2; use constant NICKNAME => scalar 12; use constant MAXBYTES => scalar 25; $| = 1; my ($client_socket,$server_data,$client_packet,$result); my $info = $ARGV[0]; # User message argv[0] my $Nickname = $ARGV[1]; # User nickname argv[1] if ($Nickname =~ s/\W//g) { print "Special characters detected, please remove them!\n"; exit(); } if (@ARGV > ARGUMENTS) { print "\nPlease no more than ".ARGUMENTS." arguments (ARGV[])!\n"; print "\nCorrect Syntax: perl Exercise_5_Client.pl 'IP:PORT NICKN +AME' (e.g. 127.0.0.1:5000 Thanos)\n\n"; exit(); } elsif (@ARGV < ARGUMENTS) { print "\nPlease no less than ".ARGUMENTS." arguments (ARGV[])\n"; print "\nCorrect Syntax: perl Exercise_5_Client.pl IP number\n (e.g. 127.0.0.1) port number (e.g. 5000)\n Nickname (e.g. Thanos)\n\n"; exit(); } if (length($Nickname) > NICKNAME) { print "\nPlease no more than ".NICKNAME." characters as nickname!\ +n"; } else { my $string = index($info, ':'); if ($string == '-1') { die "Please add ':' in your input - ".$info."\n"; } my @input = split( ':' , $info ); # creating object interface of IO::Socket::INET modules which inte +rnally creates # socket, binds and connects to the TCP server running on the spec +ific port. $client_socket = new IO::Socket::INET ( PeerHost => $input[0], PeerPort => $input[1], Proto => 'tcp', ) or die "ERROR in Socket Creation : $@!\n"; $client_socket->autoflush(1); # Send/receive immediately $client_packet = "\0"; my $first = &send($client_packet); my $receive = &receive(); $client_packet = $Nickname; my $second = &send($client_packet); my $receive_2 = &receive(); if ($receive_2 ne "OK") { $client_packet = "ERROR"; &send($client_packet); print "Client received unexpected message terminating!\n"; exit(); } # End of if receive eq OK MSG: print "Please be aware maximum length 255 characters!:\n"; do { print "Send this text to clients:\n\n"; chomp ($result = <STDIN>); if (length($result) >= MAXBYTES) { print "\nYou have exceeded the limit of characters ".length($r +esult)."!\n\n"; goto MSG; } else { my $new_line = "\n"; $client_packet = "".$result."".$new_line.""; utf8::encode($client_packet); my $third = &send($client_packet); my $receive_3 = &receive(); print "This is received_3: ".$receive_3."\n"; } } until ($result eq "END" || "end"); print "Goodbye\n"; $client_socket->close(); } # End of else condition (ARGV[]) sub send { $client_socket->send($client_packet); return $client_packet; } sub receive { # we can read from socket through recv() in IO::Socket::INET $client_socket->recv($server_data,MAXBYTES); print "The following data received form Server: (\ $server_data \) + "; print "\n"; return $server_data; } $| = 1;

I tried to enter another goto condition after end of do loop but not successfully. If I do so I lock my self in an infinity loop that I do not send messages or receiving messages, not even able to exit loop by typing end.

Any suggestions or ideas would be much appreciated.

Thanks everyone for their time and effort to assist me with my problem.

Seeking for Perl wisdom...on the process...not there...yet!

Replies are listed 'Best First'.
Re: do until loop breaks before meeting the condition
by LanX (Saint) on Jun 08, 2014 at 14:28 UTC
    ...} until ($result eq "END" || "end");

    "end" is a non-empty string and thus is the or always true!

    you maybe meant

    ...} until ( $result eq "END" or $result eq "end" );

    or even better

    ...} until ( uc($result) eq "END" );

    (see uc or lc for details)

    Cheers Rolf

    (addicted to the Perl Programming Language)

    PS: next time please try using <readmore> tags for long code! :)

      Dear Rolf,

      You are right about the condition, I was not aware that I could not bind together two conditions like this.

      Unfortunately the problem still exists, after the first user input, if the text us under the MAXBYTES = 25 (for example purposes) the loop locks and stays infinitely in. Even with the END or end text input still it is in the loop.

      Sorry about the long code, I will read about <readmore>.

      Seeking for Perl wisdom...on the process...not there...yet!
        Works for me. It keeps asking until I enter "end" or "END" (or "eNd" etc.).
        #!/usr/bin/perl use warnings; use strict; use constant MAXBYTES => 5; $| = 1; MSG: print "Please be aware maximum length ${\MAXBYTES} characters!:\n +"; my $result; do { print "Send this text to clients:\n\n"; chomp ($result = <STDIN>); if (length($result) >= MAXBYTES) { print "\nYou have reached the limit of characters ", length $result, "!\n\n"; goto MSG } } until uc $result eq "END";
        لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: do until loop breaks before meeting the condition
by Laurent_R (Canon) on Jun 08, 2014 at 15:40 UTC
    Hi, I have just tried the following code:
    use strict; use warnings; use constant MAXBYTES => scalar 5; my $result; $| = 1; MSG: print "Please be aware maximum length 255 characters!:\n"; do { print "Send this text to clients:\n\n"; chomp ($result = <STDIN>); if (length($result) >= MAXBYTES) { print "\nYou have reached the limit of characters ".length($result +)."!\n\n"; goto MSG; } } until ($result eq "END" or $result eq "end"); $| = 1;
    and it works as expected for me: it loops when I enter strings such as "foo" or "bar" and exits the loop if I enter "end" or "END".

    Having said that, there are a few problems in this code. One is that the message states:

    print "Please be aware maximum length 255 characters!:\n";
    but MAXBYTES is set to 5. The second one is the use of goto, this is widely considered to be a very bad programming practice, especially when the goto brings you upward in your code and out of a loop, and this is pretty useless in this case. Try something like this instead:
    use strict; use warnings; use constant MAXBYTES => scalar 5; my $result; $| = 1; my $msg = "Please be aware maximum length 255 characters!:\n"; do { print "Send this text to clients:\n\n"; chomp ($result = <STDIN>); if (length($result) >= MAXBYTES) { print "\nYour input has a length of " . length($result) . "; +the limit is ". MAXBYTES, "\n\n"; print $msg; } } until (uc ($result) eq "END"); $| = 1;
    although this is still somewhat clunky (but I wanted to stay close to your code). One additional question: why are you setting $| twice to the same value?

    On the problems with the goto function, please read this classical text: http://www.u.arizona.edu/~rubinson/copyright_violations/Go_To_Considered_Harmful.html.

      ehm ... he's using goto as loop control, last, next and redo are not much different.

      Than you don't print the $msg before first run like he did.

      Considering "cleanest" and "DRYest" flow control , I'd rather try this

      > perl $max_length=5; OUTER: { print "Input max is $max_length!!!\n"; while (1) { chomp( $input = <STDIN> ); last OUTER if lc( $input ) eq "end"; redo OUTER if length( $input ) > $max_length; print "- $input is OK\n"; } } __END__ Input max is 5!!! 1 - 1 is OK 12345 - 12345 is OK 123456 Input max is 5!!! 123 - 123 is OK end >

      YMMV! :)

      update

      please note that the more verbose

      OUTER: while(1) { ...

      works equally well and might be less surprising for some maintainers. :)

      Cheers Rolf

      (addicted to the Perl Programming Language)

        To: Lanx,

        Thanks, I was not even aware of: last, next and redo.

        Hmmm based on second look your solution looks simple and I ques better than mine. I think I will follow it.

        Again thank you for your time and all this information that you shared.

        Seeking for Perl wisdom...on the process...not there...yet!
        Well, I am not an anti-goto fanatic, the comment on gotos was just one out of 3 comments. I still think it is much better to use regular loop control statements (last, next, etc.), and it is most of the time best to avoid gotos altogether (except for the special goto &name construct).

      To: Laurent_R,

      Thanks for the information I was not aware that goto is bad coding.

      I removed it and followed your example.

      P.S.: The MAXBYTES = 5 is just for fast implementation purposes.

      P.S.2 About the $| = 1; I thought that it would be good to flush the buffer also at the output. Maybe I was just over doing it.

      Again thank you for your time and effort.

      Seeking for Perl wisdom...on the process...not there...yet!
Re: do until loop breaks before meeting the condition
by BillKSmith (Monsignor) on Jun 08, 2014 at 19:53 UTC
    Avoid the issue. Use a prompt module.
    use strict; use warnings; use IO::Prompt::Hooked; my %opt = ( message => "Enter text (1-255 characters) to send to clients: ", validate => qr/^.{1,255}$/, error => "You have exceeded the limit of 1-255 characters - Try + again\n", escape => qr/^END$/i, ); while ( my $result = prompt(%opt) ) { print ">>$result<<\n" }
    Bill

      To: BillKSmith,

      Nice, I had no clue about this process. It might also come in handy to other scripts. Thanks for sharing.

      Seeking for Perl wisdom...on the process...not there...yet!