Updated 2014-04-10 11:36:34 by EMJ

The often used screen name for David S. Cargo (escargo@skypoint.com and dcargo@mednetstudy.com). My home IP address is often 199.86.45.178 (from home) or 67.53.175.180 (from work), and will appear when looking at Recent Changes.

Updated slightly on 05/05/05 since it's such a funny date.

Initials? Why would I prefer to use initials with a handle like this?

I have been coding in tcl, tk, and expect since 1996.

For a few years I was a Multics [1] user, and have also used (in ancient times) CP/M-80, MS-DOS, VAX VMS, TOPS-10, old Honeywell minicomputer systems, ModComp Systems.

More recently I have used CrayOS, Solaris, Microsoft Windows (starting at 3.1), and Linux.

I did manage to attend the Tcl 2002 conference in Vancouver. Very nice.

I have started a few pages, including one with an application:

and others more philosophical


For $25/yr you can be escargot@slug.org.

(That's the yearly membership for slug.org) PSE

For not much more than that I can get my own domain name. I'm not sure a snail should be consorting with slugs. They are fellow mollusks, but still....

Pet Peeves

I may wind up doing some minor editorial (copyediting [2] [3]) changes to wiki pages that I see that have the following problems.

  • The use of "it's" instead of "its" (where the possessive is intended)
  • The use of "its" instead of "it's" (where the contraction is intended)
  • The use of "lets" instead of "let's" (where the contraction is appropriate)
  • The use of "which" instead of "that" (nonrestrictive versus restrictive)
  • Misspellings ("alot", "sepereate", "dont")
  • The use of British usage in American writing ("forwards", "backwards", "towards")
  • Redundant adjectives ("close proximity")

I won't mark these changes since I don't think they will change the meaning.

EKB I support you in this effort, but mention that the rules for "which" vs. "that" are different in the UK and the US.

escargo I know that, so I like to check to see which kind of quotations might be used (single versus double quotation marks) to guess which kind of localization needs to be done.

My tendencies toward punctuation correction have led two different people to each give me a copy of Eats, Shoots & Leaves: The Zero Tolerance Approach to Punctuation, by Lynne Truss.

neb Would that be a 'compunctuation'... a compunction for punctuation?

My Current Puzzle

May the source be with you...

I'm trying to develop an application that can, among other functions, read and process Tcl commands from a file. I want to log operations (using the tcllib logger package). Ideally, legal Tcl would be processed in a way equivalent to the source command. However, I'm seeing interesting differences.

First, some legal operations (to be stored in a file named test.tcl):
 proc requireOperation {service operation} {
     if {[string trim $operation] eq ""} {
         puts "blank operation"
     }
     return 1
 }

 set ops [list operation1 operation2 operation3 operation4]

 set service someService
 foreach op $ops {
     requireOperation $service $op
 }
 # This should be the equivalent of the code above.
 set ops [list \
              operation1 \
              operation2 \
              operation3 \
              operation4]

 foreach op $ops {
     requireOperation $service $op
 }

To run this code, you must first do
 package require logger
 set log [logger::init test]

 source process_file.tcl
 process_file $log test.tcl

This is the code that has the problem somewhere:
 # process_file.tcl - This file contains procs for executing files or
 # lists of Tcl commands.  Errors are caught and reported.  Execution
 # is not terminated at this level.  If execution is terminated, it
 # will happen at the logging proc level.

 # logObj - a logger object to use for logging
 # fileName - the name of the file to execute commands from
 # This proc reads the entire file before processing starts.
 # It does not finely diagnose why a file cannot be read.
 proc process_file {logObj fileName} {
     ${logObj}::info "Opening $fileName"
     if {[catch {open $fileName} handle]} {
         ${logObj}::critical "Failure opening $fileName"
         set result 1
     } else {
         set result 0
         set contents [read $handle [file size $fileName]]
         close $handle
        # This was added to solve one problem but it might have created another.
         set contents [string map [list "\\\n" ""] $contents]
         set listOfLines [split $contents \n]
         runCommands $logObj $listOfLines
     }
     return $result
 }

 # logObj - a logger object to use for logging
 # listOfLines - a list containing a sequence of lines to execute
 # The proc does not care where the lines came from.
 proc runCommands {logObj listOfLines} {
     set n [llength $listOfLines]
     ${logObj}::debug "runCommands passed $n lines."
     set command ""
     # Using for so that lines are counted.
     for {set i 0} {$i < $n} {incr i} {
         set line [lindex $listOfLines $i]
         ${logObj}::debug "Line $i: $line"
         append command $line
         # Allow manual exit of this loop without a real EOF signal.
         if {$command eq "EOF"} {
             break
         } elseif {[info complete $command]} {
             runOneCommand $logObj $command
             set command ""
         }
     }
 }

 # logObj - a logger object to use for logging
 # command - the command to execute
 # This proc is only supposed to be called when "info complete"
 # says that there is a complete command.  However, that is true
 # for the empty string and even a list of empty strings.
 # Don't bother to safeguard against those for now.
 proc runOneCommand {logObj command} {
     global errorInfo
     # Execute command at global level.
     ${logObj}::info "Executing $command."
     if {[catch {uplevel \#0 $command} result]} {
         puts [set errorInfo]
         ${logObj}::error "Error executing $command: [set errorInfo]"
     } else {
         puts $result
     }
 }

The problem seems to result in confused tokenization of the processed code. I get messages like:
 wrong # args:  extra words after "else" clause in "if" command

It seems like this ought to be simple, but it's not.

RJ I think I see what may be happening. Here is what listOfLines ends up looking like when passed to the next proc:
  \ proc\ requireOperation\ \{service\ operation\}\ \{ \ \ \ \ \ if\ \{\[string\ trim\ \$operation\]\ ==\ \"\"\}\ \{ {    puts "blank operation"} \ \ \ \ \ \} {     return 1} \ \} {} { set ops [list operation1 operation2 operation3 operation4]} {} { set service someService} \ foreach\ op\ \$ops\ \{ {     requireOperation $service $op} \ \} {}

See if command page - if the if command appears on a single line and ends in a continuation "\" it expects the next line to start with 'else'. Could it be seeing the "\" chars as continuations? MG doesn't think that's entirely true. It only needs an "else" keyword and clause if there's -something- there. If it's just spaces (or no characters at all) on the lines, they're ignored totally.

MG The problem is your
  append command $line

line of code. All the lines in the body of the proc are being appended into one single line (because 'info complete' doesn't return 1 until the closing } for the proc definition), so the body of the requireOperations proc is:
  if {[string trim $operation] eq ""} {         puts "blank operation"     }     return 1

which takes advantage of the fact that if doesn't need the 'then' / 'else' keywords to work, and assumes "return" is its "else" clause - and then has an extra word after the else clause, the "1". If you ended (or started) each separate command line with a semi-colon it would sort the problem, but wouldn't really be generally useable.

The same problem is likely to come up within a foreach (or an if, for that matter) when called outside a proc - if its args have multiple lines, they'll all be concatenated into one single line. Perhaps using
  append command "; $line"

would fix the problem, but I'm not sure. I'll try that now... Yup, it seems it does, at least in the test case you used on this page. I'm not sure whether it'll always work, but so far...

escargo 27 Sep 2005 - Indeed, "so far" it seems to be doing the trick. I now have my logging working to my satisfaction. Thank you.

Messages to escargo:

  • Zarutian 2005-07-25-15:34 meet me on the tclers' chat.
  • Zarutian 2005-07-25-16:07 well, I have to go off the chat for now but I will probably be on it again between 23:00 GMT and 00:00 GMT tonight.
  • Sorry; I don't chat, but feel free to send me e-mail at the addresses above.

LVwikignome - 2013-04-28 11:18:48

Good morning! I was reading one of the wiki pages on argument parsing and you mentioned developing an argument parsing strategy that worked for command line or graphical specification.

I am playing with tcl a bit, and was thinking that it would be interesting to allow:

  • ability to run command from tkcon, cmd, cygwin bash, specifying items on the command line
  • ability to have program prompt user or arguments if no GUI is available
  • ability to use a GUI if using a wish/tk/or at least program can package require Tk to get it
  • ability to drag and drop one or more files onto file browser gui controls
  • ability to use windows contextual menu "open with" function to pass one or more files

Would one application require all of this? Maybe - if one was writing a general utility like a 7zip, or file comparison, etc. program.

Anyways, I was just curious whether your efforts had resulted in anything that was available to examine and think about.

Thank you so much for all your contributions.

AK - 2013-04-29 15:51:27

I should possibly point to the Commander now, at http://core.tcl.tk/akupries/cmdr/index Not much of documentation at the moment. Examples only in the test suite.