0
votes

Doing the echo service example in the book, 'Practical Programming in Tcl & TK 4th edition' Brent B. Welch Ken Jones Jeffrey Hobbs.

Its on page 241, example 17-3. Copied it straight out of the book and its giving me the following error:

tclsh "theEchoService.tcl" (in directory: /home/<username>/Documents/Scripts/tcl)
Compilation failed.
wrong # args: should be "proc name args body"
    while executing
"proc Echo {sock} \
{
    global echo
    if {[eof $sock]} || [catch {gets $sock line}]} \
    {
        ;# end of file or abnormal connection drop
        close $sock
        pu..."
    (file "theEchoService.tcl" line 16)

Heres my full code:

#!/usr/bin/tclsh
;#The Echo Service. Socket ProgrammingPage 241, Example 17-3
proc Echo_Server {port} \
{
    global echo
    set echo(main) [socket -server EchoAccept $port]
}
proc EchoAccept {sock addr port} \
{
    global echo
    puts "Accept $sock from $addr $port"
    set echo(addr, $sock) [list $addr $port]
    fconfigure $sock -buffering line
    fileevent $sock readable [list Echo $sock]
}
proc Echo {sock} \
{
    global echo
    if {[eof $sock]} || [catch {gets $sock line}]} \
    {
        ;# end of file or abnormal connection drop
        close $sock
        puts "Close $echo(addr, $sock)"
        unset echo(addr,$sock)
    } \
    else \
    {
        if {[string compare $line "quit"] == 0} \
        {
            ;# Prevent new connections, Existing connections stay open
            close $echo(main)
        }
        puts $sock $line
    }
}

I've tried it without my escapes and still the same. Any ideas?

2

2 Answers

2
votes

The problem is this line:

if {[eof $sock]} || [catch {gets $sock line}]} \
              ^^^

That extra } is terminating the if early, which makes the } at the end of the line terminate the body of the procedure early (and the rest of what you think the body is appears as extra arguments to proc, which doesn't like it).

You're recommended to avoid using backslashes to introduce newlines like that; it's just extra visual noise. You're also recommended to use an editor which can do auto-indentation and/or bracket matching, both of which would have helped you find your problem virtually immediately.

1
votes

Don't try and make your Tcl code look like C. It is not the same language at all. Every statement in Tcl is made up of words terminated by a newline or semicolon. One way to group words is using the curly braces but these need to be on the same line as the earlier part of the phrase. You can escape the newline as it looks like you are attempting to do but this is fragile and hard to maintain because if you introduce any whitespace after your escape character you no longer escape the newline and you get the error you are seeing.

In Tcl code, put the opening braces on the same line as the code. eg:

proc Echo {sock} {
    if {1 == 0} {
        puts "something"
    } else {
        puts "do something else"
        expr {
           1 * 2 +
             3
        }
    }
}

This is explained in detail in the Tcl(1) manual page but you have to read it rather carefully to glean the details.