Version 461 of Ask, and it shall be given # 6

Updated 2008-05-05 23:52:37 by MG

Please add questions at the top of this page.

Also consider putting a **section heading** on the top of each new question.

  • Started on: 2007 May 05
  • Ended on:

TLS in Tclkit:

KCW I have been using tclkit in a limited way for some time. Recently, I've been using the tls package outside of tclkit, and now I'm trying to incorporate that portion of my system into tclkit for distribution. What I think I'm learning is that tclkit, by design, supports only a limited number of external packages, and my starkit tells me it can't find tls using either the 8.4.18 or 8.5.1 runtimes (Mac universal). Is tls not part of the tclkit runtime? I see mention somewhere of a Win build of tls 1.4 in starkit form, but (a) I'm not sure how to use this, and (b) I don't see much mention anywhere of tls in tclkit on other platforms. My suspicion is that cross-platform availability of recent versions of tls within tclkit would be a common need, but I haven't been able to figure out what I need to do. Any advice would be greatly appreciated. Thanks, Ken

LV What do you mean by a limited number of external packages? Do you mean a limit on the number of packages one can put into a starkit? See kitten - an early example of putting dozens of packages into one starkit...

MG Compared to ActiveTcl, a Tclkit looks in a very small number of places for packages, by default. (When you say you're trying to incorporate tls into your tclkit, do you mean for deployment as a Starpack?) If your starkit can't find tls, though, it likely means you need to add a

  lappend auto_path /path/to/tls

into your code, before the package require.


MG I just went to copy the contents of console.tcl (from /lib/tk8.5) into my app, to make the console available on non-Windows platforms, and noticed it has checks in there for the aqua windowing system. Does this mean the console is available in Tk on all platforms, now? I have a GUI program that others are using on MacOS X and Linux, and I want to make the console available there, but don't want to include it twice. Thanks for your help.

Mike

The built-in console is available on OS X, in 'Wish 8.5.app' at least. It doesn't seem to be available to wish8.5 or tclsh8.5 after a 'package require Tk'. Neither is it available to 'Wish' inside the Wish 8.5.app bundle (/Applications/Utilities/Wish 8.5.app/Contents/MacOS/Wish). Presumably there is some way to enable 'console show', but so far it eludes me. I'm not aware of the "standard" console working on Linux. There's always TkCon.

CJL

MG Thanks for your reply. TkCon is more than I need, really - I'll just make sure I include console.tcl in any non-Win versions. If it's not always available, I'd rather occasionally have the code there twice than sometimes be without it.


Authoring ActiveX DLLs

BMA Is there an equivalent in the Tcl world to ActiveState's PerlCtrl (part of the Perl Dev Kit)? Essentially, I'm after a way of wrapping Tcl into a standalone ActiveX DLL. I've seen TclBridge, which is fine for using other ActiveX/COM objects in a Tcl script. However I'd like to use Tcl to author a such an object. My apologies if this issue has been thrashed out long ago; I haven't been around since long ago.

(Later) After reading about tCom and StarPacks, is it possible to use a combination of these to build an out-of-process ActiveX/COM server .EXE?

Thanks in advance, Bruce.


MG Is there any good/easy way to find the ranges in a text widget that have two tags? I have a text widget with "bold" and "italic" tags, but the only way to do them is to configure the -font for the tag to be bold or italic, so you can't apply both (whichever tag is raised higher gets used). So after doing the inserting I want to search for ranges with both tags, and add a "bolditalic" tag that has both styles applied. Would've thought $text tag ranges would do it, but it seems to only take a single tag, not a list. Any help is greatly appreciated :)

aricb proposes the following solution, culminating in the proc getoverlaps, which takes two lists of ranges of the format returned by [$text tag ranges $tag] and returns one list in the same format:

 proc compareindices {i1 i2} {
     lassign [split $i1 .] l1 c1
     lassign [split $i2 .] l2 c2
     set dl [expr {$l1 - $l2}]
     if {$dl != 0} {
         return $dl
     }
     return [expr {$c1 - $c2}]
 }

 proc minindex {i1 i2} {
     if {[compareindices $i1 $i2] < 0} {
         return $i1
     }
     return $i2
 }

 proc maxindex {i1 i2} {
     if {[compareindices $i1 $i2] > 0} {
         return $i1
     }
     return $i2
 }

 proc getoverlaps {range1 range2} {
     set results [list]
     set index1 0
     set index2 0
     while {$index1 < [llength $range1] && $index2 < [llength $range2]} {
         set s1 [lindex $range1 $index1]
         set e1 [lindex $range1 $index1+1]
         set s2 [lindex $range2 $index2]
         set e2 [lindex $range2 $index2+1]

         if {[compareindices $s1 $e2] >= 0} {
             # no overlap
             incr index2 2
             continue
         } elseif {[compareindices $s2 $e1] >= 0} {
             # no overlap
             incr index1 2
             continue
         }
         # overlap
         lappend results \
             [maxindex $s1 $s2] \
             [minindex $e1 $e2]
         if {[compareindices $e1 $e2] <= 0} {
             incr index1 2
         }
         if {[compareindices $e1 $e2] >= 0} {
             incr index2 2
         }
     }
     return $results
 }

MG Thanks very much! I'll give that a try.


I'm not able to use "debug -D 1" in my linux machine. The moment expect encounters this line, it gives the debug prompt & exits the shell. Any pointers?? Thanks in advance

-Raj


I have been using the mysqltcl package for my db needs. However, I am having difficulty calling a stored procedure using mysqltcl package. It doesn't appear any of the functions allow a stored procedure call and return the results. I have tested my stored procedure outside of TCL and it works fine using the following syntax:

      call x (@myvalue);select @myvalue;

As you can see, the call to the stored procedure requires two successive statements. I have multistatement and multiresult flags on during my db connection. I have tried many of many options to which none have been successful.

Any help would be great.

Thanks in advance.


package require from embedded Tcl on Debian

RAlead Apr 10 2008. Tcl 8.4 on Debian Linux: package require from embedded Tcl

After recently recompiling an application which has Tcl interpreters embedded in it, I find that "package require" now only sees the .so file in a package directory and not the .tcl files. If there is no .so file, it sees only some of the .tcl files. I don't see anything in the Tcl documentation that suggests a change in the way "package require" works.

I also see that tcl_interactive is not defined for an embedded interpreter, which also breaks some previously working code.

Any clues would be greatly appreciated.

Lars H: Is there a pkgIndex.tcl file? (There probably should be.) What does it say? How is it generated? Recall that package require only does what package ifneeded has told it to do.

RAlead: Re pkgIndex.tcl, of course! The command executed at the tclsh prompt in the package directory was 'tcl_mkIndex . *.so *.tcl'. Regarding 'ifneeded', I've been wondering about what it might do that isn't spelled out in the man page. Specifically, the program in which the Tcl interpreter is embedded calls the package initialization routine (e.g. Tclx_Init, and similar home grown functions). As I understand it, this attaches the .so file at run time. I suspect it does nothing with the pkgIndex.tcl file. Putting 'package require my_pkg' at the top of the first script processed by the interpreter does not seem to change that, perhaps because 'ifneeded' is already satisfied.

Previously, instead of 'package require my_pkg', I sourced a home-grown proc that looks like this:

 proc require lib {
   global auto_path
   if { [string first $lib $auto_path] < 0 } {
     set auto_path [linsert $auto_path 0 /usr/local/lib/$lib]
   }
 }

Maybe there is no other way.

Lars H: That just adds an item to the auto_path, which might be needed for package require (or rather the package unknown command) to take notice of the pkgIndex.tcl file, but it shouldn't cause anything to be loaded. If it has worked for you to just call that require and then start using package commands, then you must have been relying on unknown/auto_load instead, which uses tclIndex files rather that pkgIndex.tcl files.

A package initialization C function typically does the equivalent of package provide, and after that package require is satisfied the package is already loaded; any package ifneeded script will be ignored. If the .so is not the whole package, then maybe it shouldn't do that, or alternatively only do that after it has sourced any accompanying .tcl files, but tcl_mkIndex rather assumes every file of a multi-file package to make a package provide or equivalent. Strange.

One approach that is sometimes used it to use different names for the Tcl and C parts of a mixed package, e.g. mypkg and mypkg::C-part. The user is then supposed to

  package require mypkg

which corresponds to a package ifneeded script on the form

  source /some/path/to/mypkg.tcl

and mypkg.tcl in turn contains

  package require mypkg::C-part 1.0
  package provide mypkg 1.0

where the package ifneeded script for mypkg::C-part rather has the form

  load /some/path/to/mypkg.so

i18n on MacOS X

SZ Apr 10 2008 - (I decided to do a little Tcl programming on MacOS. Tcl is for portability.)

  • The Cmd-Space input encoding key is not working in text widget
  • Russian text in text widget appears with spaces in between, like "s e r g u e y" instead of "serguey."

How to overcome those two problems? I use Wishkit for Aqua They are seem to persist for at least two years.

MG As far as I can see, the default bindings for the text widget are for the Command key + any other to do nothing. What are you expecting Command-Space to do? You'd likely need to bind to it yourself -

  bind Text <Command-Space> {do stuff}

No idea about the other problem, I'm afraid...

Lars H: In MacOS, some key combinations are bound by the system, see [L1 ]; cmd-space tends to switch between different script systems (e.g., to Cyrillic [L2 ]). If cmd-space does nothing then Tk probably doesn't go through whatever mechanism this relies on in ordinary applications, but OTOH I think Apple changes it between different OS versions, so what doesn't affect us in one version might do so in another.

Be sure to also check whether this is a font issue. If the Cyrillic letters are entered correctly but (for some reason) displayed using glyphs from (say) a CJK font, then they might happen to be padded to ideograph width; stranger things have happened. In such situations, string is your friend — try selecting the text before giving the command

  string length [$textWidget get sel.first sel.last]

"Сергей" is six characters, whereas "С е р г е й" would be eleven.


List quoting, exec, string map

MG Apr 9 2008 - I have a string in the form

  "c:\path to\my\app.exe" %1

I need to replace the %1 with an actual arg, then exec the program. I'd thought that

  exec {*}[string map [list %1 foo] $string]

would work, but the backslashes are getting stripped out (so I get the error "couldn't execute "c:path tomyapp.exe": no such file"). Is there any easy way around this? I'm not sure if it's Tcl or Windows doing the stripping. This is for a cross-platform app, and the string in question is user-provided, so I'd like to try and keep it as simple as possible, at least from the point of view of the format the user has to input the string in. Any help would be greatly appreciated. Thanks :)

peterc 2008-04-09: In Tcl, the \ character is used a modifier to the next character. \n is a newline, \t is a tab, etc. This makes Windows native paths a bit of a pain, as you can imagine. You'll need to take the user's input and use string map to change \ to \\ (or better yet, \ to /) before you make other changes. I'd suggest using the latter and present the user with 'string native $yourstring' in the output while using / as directory delineators internally.

pcam I would recommend for portability and avoid any issues with escape sequences you use something like

 set path [file serialize {c:\mypath\to my\app.exe} ]

Also, making your path a list, did seem to work for me.

 set pathl [list {c:\path to\my\app.exe} %1]
 exec {*}[string map [list %1 foo] $pathl]

MG What I'm actually doing is allowing the user to enter the appropriate system command for launching a web page into an entry widget, as a default for when the methods for launching it my code tries don't work. So what I effectively have is

  set path {"c:\program files\Internet Explorer\iexplore.exe" %1} ;# set by an entry widget's -textvariable
  set url {http://wiki.tcl.tk}
  exec {*}[string map [list %1 $url] $path] &

What was confusing me was why the backslashes were disappearing, as the string map leaves them in correctly, but then the {*} seemed to be evaluating them out, when it shouldn't. But since adding list makes it work (thanks, pcam!), I suspect it's not actually evaluation that's taking place, but conversion of the string returned by string map into a valid list, and it's that which is eating the backslashes... </rambling> Anyway, thanks for the help :)


Quoting hell or SQLite issue

pcam - 2008-03-27. I am trying to get a simple proc to add a table in my SQlite database. The proc takes 3 arguments: the dbfilename, the new table name, and a list of lists which turns out to be all the fields of the table. Each field has 3 elements: name, type and default value. All worked fine until I realized that my default value for one field is '""' (single quote-double quote-double quote-single quote), and when I try to build the SQL statement, this gets interpreted. So end result is that the table is created but the default value not properly set. Please assist, I am certain this is a simple thing

  proc AddTableToDB { DbName tablename lTableFields} {
    load tclsqlite3.dll
    sqlite3 handleDB $DbName

    # Build the ful lSQL statement to run
        set sqlCreate         "CREATE TABLE $tablename "
        # add the list of fields (name type default) comma separated
        set sqlFields [list ]
    foreach field $lTableFields {
        if { [llength $sqlFields ] } { set separator "," } else { set separator "" }
        set sqlFields [append sqlFields $separator $field ]
        }

        append sqlCreateTable $sqlCreate "(" $sqlFields ")"
    puts $sqlCreateTable

        handleDB eval ${sqlCreateTable}

        handleDB close
  }
  set lFields [list [list date NUMERIC] [list evt_actor TEXT DEFAULT {'""'}] ]
  AddTableToDB whatever.db MY_TABLE $lFields

LV So, tell us, what is it that you want in the field when the proc successfully runs? A zero length string? A null value? The 2 quote characters?

pcam You are right, I forgot the most important. I would like to have exactly '""'. When the handleDB eval is called, it should pass the full SQL statement: CREATE TABLE MY_TABLE(date NUMERIC, evt_actor TEXT DEFAULT '""') My issue I think is that list turns {'""'} into '\"\"'. See what I mean. Then after I guess eval does another round of quote/unquote.

MG Just a guess, but try changing the line

        set sqlFields [append sqlFields $separator $field ]

to

        set sqlFields [append sqlFields $separator [join $field " "]]

That should force each element of the list to be correctly shown in string form, rather than as a valid list element.

pcam Thanks a lot, it works perfectly! Makes me think I need to improve my understanding of the (subtle) differences between string and list.


Testing event-driven systems

Lars H, 2008-03-26: How would one test event-driven mechanisms using e.g. tcltest?

OK, I understand that one has to enter the event loop and let all the wanted events play out, but how does one know when the test is complete? There is of course the basic approach of letting it run for a certain amount of time and then hope everything had time to finish, e.g.

  set epoch 0
  # ...
  tcltest::test ... -body {
     after 10000 {incr ::epoch}
     vwait ::epoch
     # Construct result to be tested
  } ...

but that seems rather arbitrary to me. Furthermore it may take a very long time to test if one has to estimate worst-case time for the entire process, since some of the things one might need to wait for are timeouts; a half a minute timeout is not unreasonable in a production system. Always waiting that long even if everything normally finishes in about a second seems simply too wasteful.

One alternative I've considered is to have a watchdog that uses after info to check for other pending events and reschedules until there aren't any, like so:

  proc watchdog {period} {
     if {[llength [after info]]} then {
        after $period [list watchdog $period]
     } else {
        incr ::epoch
     }
  }
  tcltest::test ... -body {
     after 1000 {watchdog 1000}
     vwait ::epoch
     # Construct result to be tested
  } ...

Catch is, this will at best work for a single process setup, whereas IPC is the reason I'm even considering this. It also won't see pending fileevents, which are generally what will set things into motion.

Tcl is supposed to be great at both testing and event-driven programming, but what options are there for the combining the two?

Lars H, the next day: It occurs to me that using Tk might help, by providing send as a separate mechanism for communicating with subordinate processes involved in the test. Maybe the controlling process shouldn't even be part of the system being tested.


Is character in font?

MG March 24th - In the docs for font actual, it says "If the char argument is supplied, it must be a single character. The font attributes returned will be those of the specific font used to render that character, which will be different from the base font if the base font does not contain the given character." Is there any way to tell whether the font does contain the character? (I'm using the -show option with an entry widget, but if the widget's font doesn't contain the character I'd prefer to use, I'd like to default to a more basic one like *.)

Is there any way? Sure, call font actual with the character and compare the results to font actual without the character. If they are different, the font doesn't contain that character.

MG That had never occurred to me. Thanks :)


Perl Tk -listvariable

Xyem 2008-03-22 14:40 UTC - I am using the Tcl and Tcl::Tk modules for Perl and I am having issues with the -listvariable option for a listbox. I have tried passing it an arrayref, even a reference to an array ref, but I cannot seem to get it to work.

Does anyone else have experience with this and, hopefully, a graceful solution?

MG Just a guess, but are you using a local variable inside a proc? the -listvariable is always global variable, so if you're doing something like

  proc foo {} {

    set myList [list a b c]
    listbox .lb -listvariable myList
  }

it won't work, as the -listvariable refers to a global variable myList, but the myList var set on the line before is local to the proc. If that is the case, add 'global myList' inside the proc so any setting/getting inside the procs refers to the global variable, not a local one.

Xyem 2008-04-03 11:54 UTC - I'm not using the Tcl-ish nor the Perl/Tk-ish way of using the Tcl/Tk module. My code looks like this:

  my @Values = ( 'test1', 'test2' );
  my $Listbox = $Interp -> widget ( '.list', 'listbox' );
  $Interp -> listbox ( $Listbox, -listvariable => \@Values );
  $Listbox -> pack;

But, as you may have guessed, test1 and test2 do not appear in the listbox. Thanks for your input, it may provide a pointer.


Images in tiny Tcl webserver

KK I'm currently using code similar to the tiny TCL webservers to publish HTML. I now want to extend this so that it can publish files/images however I cannot find any information on how this should be done as searching for terms like "http image request" returns lots of completely unrelated results. I noticed that someone had modified one of the tiny webservers to publish images, could someone point me in the right direction?

MG Looking at mini demo webserver, I would imagine you'd want the exact same thing, but using "img/gif" or "img/jpeg", etc, instead of "text/html" in the Content-type. (For jpegs - don't think it matters for gifs - you'd need to make sure all sockets and file descriptors are configured to binary, too.)

Duoas Yes, it matters for GIFs too. Only XBM, XPM and other text-encoded image formats can be processed outside of binary mode.


Linking C program to Tcl-Tk GUI II

Miguel ST I have read below an interesting post about an interface between C and Tcl-Tk. I went there as recommended by Mr Roland (muchas gracias!): http://www.ishiboo.com/~nirva/Projects/embeded_tk/ .This is a very good example of how to do it. I wonder what the previous user (below) was intending to do, he does not mention it; but this is what I would like to do precisely myself:

* I have a translation box written in Tcl-Tk. A translation box is simply a screen cut in two. On the top we enter the text to be translated and the translation comes out on the bottom. My application does not translate however: it corrects Spanish spelling and syntax mistakes (for students of Spanish as a second language).

* The engine (the syntax corrector, the spelling corrector and the database manager) are all written in C. To correct a sentence, the user clicks on the Correct button located in the right center of the screen after entering the sentence to be corrected. At that point the C program takes over.

* Now all I'd like to do is compile the Tcl-Tk GUI and the engine and database manager written in C into one single exe. I obviously would need to acquire Tcl-Tk libraries to achieve that purpose. But which libraries?

* I need to add a small detail: the C engine is interactive; it asks clarifications from the user. Therefore it is not simply a C program that runs without interruption.

I'd need a step by step list of instructions about how to achieve this and I wonder where I can find this list. A step-by step tutorial in fact. If I can be provided with such a tutorial, I'll translate it into Spanish and I can ask around for translations into other languages. There are a lot of forums on internet for learners of C and C++ and many are in Spanish. Right or wrong, C is still recommended as the starting language. In most cases, GTK+ is recommended as a GUI for C engines. However I believe Tcl-Tk is much easier to program and much better than GTK+ and young newcomers could be attracted to Tcl-Tk if a quick way to interface a C program and a Tcl-Tk GUI was provided for them. I believe that by posting the tutorial in these forums, many youngsters would be attracted to Tcl-Tk. Thanks again!


Background image

MG March 13th 2008 - I've not fully kept up with changes in 8.5; does anyone know of the best way now to show a background image in a text widget?


Searching unsorted list

MG March 12th 2008 - I have a list of sublists, in the form

  set list [list [list 0 foo] [list 5 bar] [list 12 baz] [list 27 boing]]

Given any number, I need to find the last list element whose first subelement is lower than that number. So for the number 9, for instance, it would return 1, or the element {5 bar}. (Hopefully that makes some sense.) Can anyone suggest an efficient way to do it? The only thing springing to mind at the moment is lsorting and looping until I hit a higher number, but I'm sure there must be a better way... - RS Looping (iteration) is unavoidable. With a sorted list (-index 0 -integer) you can expect an average of half the list length of comparisons, while on an unsorted list, you have to traverse it to the end in all cases. But are you maybe after a comb-like functionality?

MG Thanks for the reply. What I'm actually doing is trying to keep track of when pieces of text were inserted into a text widget. My idea was to keep a list of sublists, the first element being the position of the first character entered at a specific time, and the second element being the time (most likely clock seconds) they were received. My plan was that when the time for a particular point in the text widget needed to be displayed, I'd just find the element whose number of characters was closest (but below) the character index to know what time it was inserted. But I think I may simplify it and do it on a per-line basis, instead of per-character. (It's for a client app, and the server only sends in whole lines, so even if the line isn't received in one read, the time the first char was retrieved is good enough.) Just reading back over what I've typed makes what I was thinking of seem ridiculously overly-complex, and makes me wonder what the hell I was thinking. :p


Growl notification

CJL -11-03-08 I'm on OS X, and trying to make use of the notification system growl [L3 ], which claims to offer, amongst others, a Tcl binding. The source for the bindings is available as a separate download, which suggests to me that it should be possible to build it on its own. Having failed miserably to get anywhere with that, I downloaded the source for Growl itself, which includes the bindings in a subdirectory. Growl itself builds fine in XCode (a few warnings), but doesn't build the binding by default. The Makefile for the bindings appears to need some paths adding before it will work (it can't by default find some Growl header files), but even then the link stage fails because of some unresolved symbols. Now I'm clearly out of my depth, having no Mac-specific experience and no Objective-C either. In fact not much that's not pure-Tcl. The Tcl extension doesn't appear to get much attention from the Growl devs - the only mention on the forums is talk of it failing to build. So I'm hoping someone on here already knows, or is interested enough to find out, what it is that needs to be done to make this potentially useful tool available to Tcl scripts. (I currently 'exec growlnotify', but that seems like a heavy weight solution.)


Expect regexps

Greenmoss So according to the Expect documentation, the best place to ask Expect questions is in the Tcl community. That being said, here's an Expect question:

I have an Expect script containing this:

while {1} {

   expect {
      eof           break

... (some others)

      -regexp ".*\] " {send "\r"}
   }

}

So the question is, if I try to use -regexp "[[.*\]" it never matches. Is there something I'm doing wrong here?

MG I would guess you need to escape the square brackets more, and use

  -regexp "\\\[.*\\\]" {send "\r"}

That way, it'll get through the Tcl parser as

  \[.*\]

leaving a backslash to escape the brackets in the regexp engine (otherwise they'll parse as the start/end of a character class, rather than literal square brackets).

AMG: I almost always put regular expressions in {braces} so that I don't have to worry about Tcl interpreting any of the characters. For example:

 -regexp {\[.*\]} {send \r}

In my opinion, this is much easier to read than MG's code. Also notice that it's not necessary to put quotes around \r. You might prefer them as a matter of style, but you're also free to leave them out.


Linking C program to Tcl-Tk GUI

Serge Is there a very simple list of instructions for a beginner about how to link a program written in C to a Tcl-Tk GUI? If so, this could help make Tcl-Tk known greatly internationally. Thanks!

Lars H: A simple list of instructions is probably hard, since there are many different ways to do this kind of thing. Reading Extending Tcl could be a start, though.

LV Serge, what more exactly is it that you are trying to do? For instance, if you take a look at the Tk source code, it is set up, after building the Tk library, to create a C program which makes use of Tk. That program is called wish. There is certainly code there to look at.

Until we know more about what it is you are trying to do, it is hard for us to help much. There is mghello I think, which was an attempt to provide a really simple C mainline which sets up and calls Tk. I don't know that it is up to date, though.

fr see an example about embedding Tk into a native Win32 GUI http://www.ishiboo.com/~nirva/Projects/embeded_tk/


Piping data to gpg

BAI 2007-03-03 Anyone knows how to call gpg from Tcl in a way that input and output can be given as Tcl-strings. I'm thinking of something like

 set encryptedString [gpgEncrypt "password" "content to encrypt"]
 set decryptedString [gpgDecrypt "password" "content to decrypt"]

The following works, but only if the encrypted output is written to a file, which I would like to avoid:

Have you considered using the exec command rather than a pipe, and passing the input via <<?

BAI Yes, i tried that, but couldn't find a combination of parameters, pipes and redirections. Furthermore, I did not find a way to submit the passphrase. The following line works, but then the passphrase could be seen in the process-list, couldn't it?

 echo thisismypassphrase|gpg --passphrase-fd 0 ...

You tried using <<? Can you show us what you tried? Using << seems to work for me. I've never used gpg before but I was able to encrypt and decrypt a simple message:

 exec gpg.exe -ac --no-tty -o - --passphrase-fd 0 --batch --output gpg.out << "my passphrase\nmy data"
 exec gpg.exe --no-tty -o - --passphrase-fd 0 --decrypt gpg.out << "my passphrase"

BAI Thanks, your solution works perfectly. I was trying to redirect output via ">>", which only works for files. However, the following works:

 catch { exec gpg -ac --no-tty -o - --passphrase-fd 0 --batch --output - << "my passphrase\nmy data"} encrypted_string
 catch { exec gpg --no-tty -o - --passphrase-fd 0 --decrypt << "my passphrase\n$encrypted_string"} decrypted_string

 proc encryptToFile {pass content outfile} {
   if {[file exists $outfile]} {
     file delete $outfile
   }
   set fd [open "|gpg -ac --no-tty --command-fd 0 --passphrase-fd 0 --batch --output $outfile" "r+"]
   puts $fd $pass
   puts $fd $content
   close $fd
 }

 proc decryptFromFile {pass infile} {        
   set result ""
   catch {
     set fd [open "|gpg --no-tty -o - --passphrase-fd 0 --decrypt $infile" "r+"]
     puts $fd $pass
     flush $fd
     set result [read $fd]
     close $fd
   }
   return $result
 }

 encryptToFile "yummy" "encryption\ntest\n" foo.txt.gpg
 set originalContent [decryptFromFile "yummy" foo.txt.gpg]

Width in characters of text widget

he 2007-02-22 I want to know the width (in characters) from a text-widget. I tried the following:

 text .t
 pack .t -fill both -expand 1
 .t cget -width

The last row returns 80 even after resizing the window with the mouse. Is this a bug? What is the correct way?

WJP 2008-03-02 What you're getting is the "desired width", not the actual width. As far as I know, there is no way to get the actual width in characters. That may not be a bug, since if the font used is not fixed width, there is no such value, only a width in "average characters". One thing you can do is retrieve each line of text and determine its width using font measure. The maximum will be the width of the text widget. However, that assumes that each line that you retrieve is actually displayed as a line, which, I believe, need not be true. You could also use wm geometry to obtain the width of the text widget in pixels, then use font measure to determine the (average) number of pixels per character and divide the text widget width in pixels by pixels per character to obtain the width in characters.

MG Probably not as good as using font measure and the window geometry, but you could also do something like

  $widget insert 1.0 [string repeat a 500000]
  $widget count -chars 1.0 "1.0 + 1 display lines"
  $widget delete 1.0 end

to insert a really long string which will be wrapped, count how many chars are displayed on the first visual line, then empty the widget.

he 2008-03-03 Thank you for the answers. The thing with the "desired width" is something strange. Everytime we use "configure option value" the value is an desired value. If the widget uses this value it becomes the actual value. Changing the textwidget size with the mouse should like using "configure -width width". In both situations we ask the textwidget to change his width. And in both situations I expect that "cget -width" returns the actual value. If we say there is a different between this two situations, this means the textwidget should never change its size, when user tries to change it with the mouse. Because the programmer has desired the -width and there is no reason not to use the value. In fact we have at least an unclear documentation.

I found the comment from jenglish on sourceforge to the same problem:

The -width option specifies the application's desired width in characters, not the actual width of the widget.

The widget uses this value (and the -font, and other options) to request a width in pixels to its geometry manager. (Use winfo reqwidth to see the widget's requested width).

The actual width is determined by the geometry manager once geometry propagation completes. winfo width returns the actual width in pixels of the widget. The widget may end up larger or smaller than winfo reqwidth, e.g., if the user resizes the window. This does not change the value of the '-width' option.

IOW: this is behaving as expected. (Most Tk widgets with -width and -height options work this way - the options specify a desired size, they don't reflect the actual size.)

Perhaps this text can be included in the manpage


Multiple listboxes

crv I have a routine that builds 25 to 35 listboxes, depending upon the supplied data, and is giving me trouble. This is the code:

   proc pCrSlBx {W Tab} {
        global lData

        set Pnt [lsearch -ascii -glob $lData(descval) "A*"]
        set Val(Ds) [lrange $lData(descval) 0 [expr {$Pnt-1}]]
        set Val(Op) [lrange $lData(descval) $Pnt end]
        set X 0 ; set Y 1
        foreach Lst $Val($Tab) {
                set Col [lindex [split [lindex $Lst 0] -] 0]
                set Pnt [lsearch -ascii -glob $lData(deschdg) "$Col|*"]
                set Lbl [lindex $lData(deschdg) $Pnt]
                set Lbl [lindex [split $Lbl |] 1]
                label   $W.lbl$Col -text $Lbl
                listbox $W.lbx$Col -width 20 -height 5 -yscroll "$W.sbv$Col set"
                scrollbar $W.sbv$Col -command "$W.lbx$Col yview"
                foreach Itm [lindex $Lst 1] {
                        $W.lbx$Col insert end $Itm
                }
                grid $W.lbl$Col -row [expr {$Y-1}] -column $X
                grid $W.lbx$Col -row $Y -column $X
                incr X
                grid $W.sbv$Col -row $Y -column $X -sticky ns
                incr X
                if {$X == 10} {set X 0 ; incr Y 2}
        }
   }

   set lData(deschdg) [list aa|dia ab|we ac|me ad|to ae|add af|thus AA|dud]
   set lData(descval) [list {aa-2 {{bus} {dog} {cow}}} \
        {ab-5 {{bus} {dog} {cow}}} {ac-10 {{bus} {dog} {cow}}} \
        {ad-22 {{bus} {dog} {cow}}} {ae-33 {{bus} {dog} {cow}}} \
        {af-35 {{bus} {dog} {cow}}} {ag-41 {{bus} {dog} {cow}}} \
        {AA-42 {{bus} {dog} {cow}}}]
   pCrSlBx "" "Ds"

The problem is that I can select something in one listbox but when I try to select something in another listbox the original selection is removed such that only a single selection can be made from the entire group of listboxes. What am I doing wrong?

Bryan Oakley Read up on the "-exportselection" option of the listbox. In short, you want to set that option to false.

crv It worked! Thanks


Interfacing with C

Nicolas Can I find practical examples anywhere that would explain how to interface a C application with TCL? For example, how would the printfs be rendered in C so that Tcl reads them (via a text file?)? In the same breadth, how could we set-up out the TCL code so that it reads a letter or number entered by a user; this letter having to be transmitted to a C app. Not easy!

Lars H: Are you talking about embedding or IPC here?

A second question: In a Tcl-Tk editor under Windows I have set up Open1, Open2, Open3 and Open4 instead of one single Open located in File (under New). Now when I click on each one, I'd like the program to simply let me view the contents of the selected directory and if I open a file in that directory, then the directory becomes the default directory, the working directory but not before that. I put the following code for each Open: -command {cd /Book1/a01 open.file} Unfortunately the CD command changes the default directory when I simply want to view the contents of the directory.

What is the syntax I should use to simply look at the contents of a directory; in other words, what should I change CD to?

Lars H: One answer might be to use glob, but perhaps you're more after displaying the directory in a tk_getOpenFile-like dialog? Either way, the operation is complicated enough that you should put it in a proc, e.g.

  -command {open_in_dir /Book1/a01}

  proc open_in_dir {dir} {
     set file [tk_getOpenFile -initialdir $dir]
     if {$file == ""} then {return}
     cd $dir
     edit $file ; # Or whatever the editor's open file command is
  }

Canvas reacting to window resize

I have an application creating sketches on a canvas in an toplevel window. If the toplevel's size is changed by the user I want to redraw my sketch so it fills the complete canvas again (which is packed with -fill both -expand yes). Is there something like an WM_REDRAW_YOURSELF which is sent to the toplevel on which I can react?

MG I think the answer is to bind to the <Configure> event. thgr Thank you very much - read the bind help page several times and never noticed that <Configure> is exactly what I want.


File naming conversions from Unix to Windows

There are times when I would like to copy files from a Unix filesystem to a Windows filesystem - for instance, if the Windows file system is on a USB hard drive system.

When I do a Windows Explorer drag and drop from a window looking at Unix (via Samba) to the usb device's window, the various files are copied - but some pop up an error saying that a particular filename is not a valid name on Windows.

Is there some Tcl code that could a) look at a string and determine whether or not the string could be used as a valid Windows file name, b) consistently modify the string into one that could be used as a valid windows file name?

Duoas Sorry for the late response. Windows filenames have several restrictions. They may not be one of

 - aux
 - con
 - prn

nor may they contain any of the characters < > ; " | / \ or #0..#31 (#128..#255 are OK though!) When reading and comparing filenames, case is not significant, but when writing filenames it is. (This should not be a problem coming from a *nix environment.) I hope the following little proc to be useful to you.

   # Convert a Unix filename to a Windows filename.
   # Invalid characters are converted to underscores (_).
   # If (spaces) then convert space chars to underscores.
   # If (separators) then convert \ to underscores.
   # Converts "aux" to "auxx", "con" to "conn", and "prn" to "prnn".
   #
   proc winify_filename {
     filename
     {spaces      false}
     {separators  true}
     } {

     regsub -all -- {[\00-\37<>;"|]} $filename _ result

     if {$separators} {
       regsub -all -- \\\\ $result _ result
       }

     regsub -all -- / $result \\ result

     if {$spaces} {
       regsub -all -- { } $result _ result
       }

     regsub -all -- {^(:?(.*\\)?)(au(x)|co(n)|pr(n))(:?(\\.*)?)$} $result {\2\3\4\5\6\8} result

     return $result
     }

Enjoy!


reference to a proc

reminder 080125,

I need to call a particular proc (let's call it "base-proc") using various proc names, which are defined at runtime.

I first tried to figure out on the web whether I can dynamically create a proc referencing another proc. So I could call e.g. "proc-A" which would in actual fact be "base-proc". However, I was not successful and couldn't find anything in this direction.

Then I tried to just create procs dynamically that are calling "base-proc". But for some reason it works in my simple tclsh within Cygwin.... but it doesn't within the application I have to embed it into. <--------- snip showing the concept -------->

proc base-proc { i } {
    puts $i
}

proc define-individual-proc { individualName } {
    proc individual-proc-$individualName { i } {
	base-proc $i
    }
} 

proc define-individual-procs {} {
    define-individual-proc "A"
    define-individual-proc "B"
    define-individual-proc "C"
} 

define-individual-procs 

individual-proc-A 12345

<--------- snip showing the concept -------->

Q1) Any better idea than the concept above?

Q2) Any idea why the concept above may not work within a more complex environment?

Thanks.

LV 2008-Jan-25 I suspect that the problem is that, in your example about, the name you are defining inside define-indivudal-proc is a local variable, which is deleted when the proc returns. Take a look at dynamic procs as performance monitors for an example.

cjl 2008-Jan-25 I think 'interp alias' is what you (reminder) want. It will let you call procedures via alternative names, e.g. given the original procedure 'realProc', define an alias to it called 'aliasToProc'

  interp alias {} aliasToProc {} realProc

Another feature that may or may not be of interest is that the mechanism allows you to define arguments to the original procedure, e.g. to define a proc 'err' that prints it's arguments to stderr:

  interp alias {} err {} puts stderr

(the effect of that is best seen in a wish console, as stderr will be rendered in red)


socket keep-alive

FH 080124,

In other languages, the socket command has a keep-alive switch which will make sure the TCP connection is not closed even when it is idle for a while. How do you implement this in TCL?


\x-notation

fr 080123, I get unexpected characters with string assignement in \x-notation. Characters in the decimal range from 128 to 255 are written as \x01 - \xff. This appears when a valid hexadecimal character follows the sequence \x... An example with the german word for sweetness:

set unicode S\u00fc\u00dfe -> Süße

set hex S\xfc\xdfe -> Süþ

expect a sharp s as above, but get a lower Icelandic thorn \u00fe.

set other_hex S\xfc\xdf\e -> Süße

is this intented? it works different in Python and Javascript.

If you read the documentation on \x it says "Any number of hexadecimal digits may be present; however, all but the last two are ignored". So what you see is expected. It is often recommended to use \u to avoid ambiguity.


Keyboard Enhancer using TCL

RPR I'm looking for pointers to any work done on a desire of mine. I'm running under Windows 98, (maybe soon XP) and I want to have the ability to map the keystrokes going to a program. Specifically, say, I'm running Word in one window, Excel in another, and Notepad in a third. If my system focus is on the Word window, and I press ctrl-F2, I want the Word executable to get a keyboard input that would be generated by pressing numeral 1. Similarly for focus on Excel, except it would get a 2, and if the focus was on Notepad, it would get a 3. All other I/O (mouse, display, file I/O) would be unaffected. All existing keyboard enhancers for Windows that I'm aware of only allow one value to be substituted for each keyboard key . What I envision is a TCL/tk "wrapper" that I would write to run each executable and provide the desired mappings for that executable. I'd appreciate pointers to people or work that's been done, (or advice, like "don't even think about doing that . . . ."), or Windows keyboard enhancers that meet my needs.

Duoas Unfortunately, I think this task is beyond Tcl. You need to use a system-wide keyboard hook, which must live in a DLL. Your best bets might be one of C, C++, or Delphi.

RPRumble Not sure I agree, yet. I'm thinking along the lines of one Tcl wrapper for one executable (say Excel) that would substitute certain keystrokes. A different Tcl wrapper would substitute keystrokes for say, Word. I think this does not require a *system-wide* keyboard hook, but it does require passing changed keystrokes to the executing program, and having the executing program have video, sound, file access to the operating system.

HE On XP (and W2000) you can try twapi. In chapter 'Keyboard and mouse input' there are commands register_hotkey, send_keys and send_input.

Duoas Well, I've never tried to do what you want, so I can't be 100% sure. But all those programs are COM/OLE enabled, so I think you are going to have a really hard time keeping focus on your "wrapper". But even if not, going around the ways of send_keys and the like is doing things the hard way. Just use a hook. It is simpler and less can go wrong.


Compiling of a C program in Dos to Windows

Nicolas (Friday December 14th 2007)I would like to integrate a C program to my Tcl application. The C program was written for Dos and unfortunately my C compiler (DevC++) doesn't seem to even be able to read the source-code. Can anyone share ideas about how to solve this problem? Thanx!

Duoas If you mean "I want to update my ancient, sourceless C program to a Windows GUI program" then check out Expect [L4 ].

LV It seems to me that the first step would be to figure out what exactly the old code was doing, and see if you can create a piece of C code that is recognized by your C compiler. The next step would be to try and figure out how you want to integrate the two applications - is it sufficient to call the C program from your Tcl program? If so, you might not even HAVE to get your compiler to build the program - just use the binary you have now.

If you are determined to either put tcl into the C program, or change the C program into a Tcl command, that is going to take a lot more work than will likely to be able to be addressed on this web page.


Windows Event Log (XP/2000/2003) on Tcl 8.3

SH Is there any tcl package (similar to twapi) that can read the event log for windows 2000/2003 and XP? I just need to read the contents of the event log and be able to get the event information. Unfortunatly twapi needs tcl 8.4, and at this time i cannot upgrade to 8.4, i am running 8.3. Thanks.


SYLK Files

GWM how do I format this http: http://en.wikipedia.org/wiki/SYmbolic_LinK_(SYLK ) OR [L5 ] - in the first need to add the right bracket manually as the Wiki removes it from the link; in the second the open [ is converted to a g!.[http://en.wikipedia.org/wiki/SYmbolic_LinK_(SYLK )]

LV Submit the problem to http://code.google.com/p/wikitcl/issues/list - this is where bugs for the wiki go.

MG I think I recall people getting around a problem like that in the past by URL-encoding the problem characters - %28 and %29 in place of ( and ), in this case. Though LV's comment is definitely the better long-term solution.


Jacl and Sockets

FH I have a problem with JACL, which is roughly TCL version 8.3. How can I find out which port i am using when i use the socket command in order to get the next available port?

What I do is

  set serverChan [socket -server accept 0]              ;# Create a server socket
  set serversocket [lindex [fconfigure $serverChan -sockname] 2]

The problem is fconfigure doesn't support the switch -sockname I get the error message bad option "-sockname": must be -blocking, -buffering, -buffersize, -encoding, -eofchar, or -translation.

I cannot use hardcoded port numbers.

DKF: Sounds like a FRQ for Jacl to me...


Modelling Data in 3D

Kurt My question is basically how to model the data in an array into 3d spheres or into a terrain.I have the following code in tcl. This code displays only gradiated colors in 2d.

  package require tcl3d

  # Definition of Global data
  set wdt 400
  set hgh 400

  #Rotation Angle used in Display
  set a 0

  #    Data to Visualize
  #         j
  #     ------------>
  #     |
  #   i |
  #     |
  #     V
  #
  set data { \
    { 1.3 1.8 2.2 2.6 3.0 3.3 3.6 3.9 4.1 4.3 4.4 4.5} \
    { 1.3 1.8 2.2 2.5 2.9 3.2 3.4 3.6 3.8 4.0 4.1 4.1} \
    { 1.4 1.8 2.1 2.5 2.7 3.0 3.2 3.4 3.5 3.7 3.7 3.8} \
    { 1.4 1.7 2.1 2.4 2.6 2.8 3.0 3.2 3.3 3.3 3.4 3.4} \
    { 1.4 1.7 2.0 2.3 2.5 2.7 2.8 2.9 3.0 3.0 3.0 3.0} \
    { 1.4 1.7 2.0 2.2 2.4 2.5 2.6 2.7 2.7 2.7 2.7 2.6} \
    { 1.5 1.7 1.9 2.1 2.3 2.4 2.4 2.5 2.5 2.4 2.3 2.2} \
    { 1.5 1.7 1.9 2.0 2.1 2.2 2.2 2.2 2.2 2.1 2.0 1.9} \
    { 1.5 1.7 1.8 1.9 2.0 2.1 2.0 2.0 1.9 1.8 1.7 1.5} \
    { 1.5 1.7 1.8 1.9 1.9 1.9 1.9 1.8 1.7 1.5 1.3 1.1} \
    { 1.6 1.7 1.7 1.8 1.8 1.7 1.7 1.5 1.4 1.2 1.0 0.7} \
    { 1.6 1.7 1.7 1.7 1.7 1.6 1.5 1.3 1.1 0.9 0.6 0.3} \
  }

  # array sizes
  set nl 12
  set nr 12

  #
  # Visualization procedures
  #
  proc get { x y } {
   lindex [lindex $::data $x] $y
  }

  proc square { x y r g b } {
      glColor3f $r $g $b
      glBegin GL_POLYGON
          glVertex2f  $x           $y
          glVertex2f  $x           [expr $y +1]
          glVertex2f  [expr $x +1] [expr $y +1]
          glVertex2f  [expr $x +1] $y
      glEnd
  }

  proc planet { w } {
       #set diffuse  "$r $g $b 1.0"
       #glMaterialfv GL_FRONT GL_DIFFUSE $diffuse
       #glutSolidCone 2 8 12 12
        glutSolidCube $w
  }

  proc showdata {  } {
    for {set i 0} {$i < $::nl} {incr i} {
          for {set j 0} {$j < $::nr} {incr j} {
                  set r [expr [get $i $j] / 4.5]
                  if { $r < 0.33 } {
                          set x $j
                          set y [expr $::nl - $i -1]
                          #glTranslatef $x $y 0.0
                          #planet $r
                          square $x $y 1.0 1.0 $r        
                  }
                  if { $r > 0.33 & $r<0.66 } {
                          set x $j
                          set y [expr $::nl - $i -1]
                          #glTranslatef $x $y 0.0
                          #planet $r
                          square $x $y 1.0 $r 1.0
                  }
                  if { $r > 0.66 & $r<1.1 } {
                          set x $j
                          set y [expr $::nl - $i -1]
                          #glTranslatef $x $y 0.0
                          #planet $r 
                          square $x $y $r 1.0 1.0
                  }

          }

          #glTranslatef $x $y $r
          #planet $r 

    }
  }

  # 
  # Basic skeleton of an TCL3D program
  #
  proc tclCreateFunc { toglwin } {
      glClearColor 1.0 1.0 1.0 1.0
  }

  proc tclReshapeFunc { toglwin w h } {
      set ::wdt $w
      set ::hgh $h
      $toglwin postredisplay
  }

  proc tclDisplayFunc { toglwin } {
      glClear GL_COLOR_BUFFER_BIT

          glMatrixMode GL_PROJECTION
      glLoadIdentity
      glViewport 0 0 $::wdt $::hgh
      glOrtho -1.0 [expr $::nr + 1] -1.0 [expr $::nl + 1] -20.0 20.0

      glMatrixMode GL_MODELVIEW
      glPushMatrix
        glLoadIdentity
        glTranslatef [expr  $::nr /2] [expr  $::nr /2] 0
            glRotatef $::a 1.0 0.0 0.0
            glTranslatef [expr -$::nr /2] [expr -$::nr /2] 0
        showdata
      glPopMatrix

     $toglwin swapbuffers
     glFlush
  }

  frame .fr
  pack .fr -expand 1 -fill both
  togl .fr.toglwin -width $wdt -height $hgh -double true \
                   -createproc  tclCreateFunc            \
                   -reshapeproc tclReshapeFunc           \
                   -displayproc tclDisplayFunc 

  grid .fr.toglwin -row 0 -column 0 -sticky news
  grid rowconfigure .fr 0 -weight 1
  grid columnconfigure .fr 0 -weight 1

  bind . <Key-Escape> "exit"

  #
  # Additional Interactions
  #
  proc down { } {
    set ::a [expr $::a + 1.0]
    .fr.toglwin postredisplay
  }

  proc up { } {
    set ::a [expr $::a - 1.0]
    .fr.toglwin postredisplay
  }

  bind . <Key-d> "down"
  bind . <Key-u> "up"

Local Sockets

Idarac My questions relate to connecting using Localhost.

1. Supposedly the block of IPs from IP 127.0.0.1 to 127.0.0.32 are all local host. For 2 apps to connect on a socket can we specify which IP we want to use. Or can we circulate through all IPs from 127.0.0.1 to 127.0.0.32 until a connection is made. I have a concern over using the loopback address 127.0.0.1 being inspected and blocked by firewall settings.

2. Given that many more than one app can connect/communicate on ONE port. Can we pick a port and make it standard on our app? … are there any considerations as to which port we choose … i.e. what happens if we decide to use port 80? Will our communications conflict/interfere with a web server service installed on the same host? If the connection on port 80 fails do we need to try an alternative … like trying another IP or a dynamic port search…

3. SSL What are the implications of communicating over localhost if we do this over SSL? Can we still use the same standard IP & port?

Lars H: Re 1: That 127.0.0.1 should be blocked sounds odd, but I think it is usually handled differently than other IP addresses. That probably applies equally to all 127.0.0.? addresses, however.

Lars H: Re 2: At any time, only one process can have a port open as server. (There is a standard, although somewhat ugly trick for a program to detect if another instance of it is already running on a machine that relies on this. The program opens a particular port when it starts and keeps it open for as long as it runs — that way, if you try to start another instance of it, the new program will fail to open the port and detects it is not the first.) Opening ports with numbers <1024 usually requires special privileges.

Lars H: Re 3: I believe this is done by first establishing the connection normally and then stacking SSL encryption on the socket channel (not the server socket channel).

DKF: The only reason for using SSL to connect to localhost is so that the client and server can authenticate to each other. But the authentication is really quite low value (both have access to the same filesystem under normal circumstances!) and other approaches are available (e.g. it's possible for both server and client to check what process has open the other end of the socket). Usually the overhead (both computation and management) of SSL isn't worth it for local sockets.


Client/Server

Idarac Thanx again to everyone for helping me get this far. I have a couple other questions.

In my client app right now I use the IP Address and the port to make a socket connection with the server app. How would 2 applications connect using a socket with each other without an IP address. Can more than one client connect at the same time on the same port with a TCL app?

If both of your apps are tcl apps, there's no easier way to make them communicate than through the comm extension [L6 ].

Can anyone comment on using pipes or shared memory as opposed to using sockets to connect? Inventory of IPC methods

Idarac One app will be a QT app the "listener" will be a TCL app. Is it possible to use a socket on a computer with no network stuff on board? I want to have 2 apps communicate with each other using sockets but the host computer may not be networked just standalone. It also has to be portable across Windows, Linux and Mac OS.

MJ - As long as the OS provides an IP stack this should be possible. If the machine has a network card (does not need to be connected), this is probably the case. I am not certain what will happen if no network card is available.


Blowfish Encryption

muukav

package require blowfish

puts "[blowfish::blowfish -dir decrypt -key STNkeySTNkeySTNk [binary format H* [blowfish::blowfish -hex -dir encrypt -key STNkeySTNkeySTNk muukav]]] hohoho"

same example in a more readable way:

set pw [blowfish::blowfish -hex -dir encrypt -key STNkeySTNkeySTNk muukav]

puts "[blowfish::blowfish -dir decrypt -key STNkeySTNkeySTNk [binary format H* $pw]] hohoho"

Why does these only return "muukav" and not "muukav hohoho"?

RS: Maybe the blowfish::blowfish result has extra \NUL bytes at the end? Tcl can stand that, but puts might terminate at a NUL byte.

muukav: lappend terminates at a NUL byte too, if that's the case. Anyhow, how could I return the decrypted data without the extra \NUL byte(s)?

LV The problem appears, to me, to be elsewhere:

$ cat t.tcl
set a ""
append a "abc" [format %c 0x000] "xyz"

puts $a
set b [split a]
lappend b "test"

puts $b 
$ ./t.tcl
abcxyz
abcxyz test
$ ./t.tcl | od -bc
0000000 141 142 143 000 170 171 172 012 141 142 143 000 170 171 172 040
	   a   b   c  \0   x   y   z  \n   a   b   c  \0   x   y   z    
0000020 164 145 163 164 012
	   t   e   s   t  \n
0000025

Note the \0 in the output - puts does NOT stop at a NUL, nor does lappend.

File a bug on this at http://tcllib.sf.net/ ...

muukav: done. thanks for the help, appreciated =)


Foreign DLLs

LGJ Newbie Question about using non-tcl DLLs I am looking to write some tests for a piece of hardware using an exisiting (non TCL) API, however, I am a little confused. I know I have two choices; use the tcl library in a C++ application or write an extension to the existing Tcl framework. My confusion starts here. Normally I write my C++ app in visual studio. I set my project settings to my include path (for my .h) files and also to my lib path for my dll. So far in the Tcl extension examples I've seen, people have been including their 3rd party DLL's in the pkgIndex file (which I understand). My question is if I call one of my API functions from a tcl script, how is it going to work or even compile if I've never specified where the *.h files are located? Is my only option to embed the Tcl interp into an existing app and script my API calls from there?

I've been following ex 47-1 in Brent Welch's "Practical Programming in Tcl and Tk" which is great, however the dll that he links in in that example seems to already be known to Tcl.... Sorry for the long winded quest. I appreciate any and all help/advice!!

GPS - I think you should look into load, and some of the extension examples. The basic sequence nowadays is like this:

#include <tcl.h>

int Ext_Init (Tcl_Interp *interp) {

 if (NULL == Tcl_InitStubs (interp, TCL_VERSION, 0))
  return TCL_ERROR;

 if (TCL_ERROR == Tcl_PkgProvide (interp, "ext", "0.1"))
  return TCL_ERROR;

 /* Call Tcl_CreateObjCommand to create your commands for this interp */

 return TCL_OK;

}

Compile with gcc -shared -DUSE_TCL_STUBS ext.c -o ext.so /path/to/libtclstub8.5.a and you should have an extension that works with load.

In Windows if you're using MinGW the sequence is something like:

  gcc -DUSE_TCL_STUBS -c ext.c  ;  dllwrap ext.o /path/to/libtclstub8.5.a --def ext.def -o ext.dll

ext.def consists of:

 EXPORTS
 Ext_Init

What's New with WubWikit?

aotto8 nov 2007 it seems that the tcl wiki technology has done a bing improvement in usability and technology .... what i don't undersand is the relationship between the old wikit and the new technology.

  1. is the new technology available for download as the old wikit was ?
  2. can the new technology used as stand-lone application like the old one ?

-> thanks for your help

LV See WubWikit for some additional information. I believe the code for the new generation of the wikit is available.


SNMP

Vish 11/07/07 - Hi Folks,

I am trying to test some SNMP Mibs using Tnm/Scotty package. I see that SNMPv3 is not listed as one of the version supported. Is that really the case or it is just that the page is out of date.

If SNMPv3 is supported by Tnm, which version of Tnm should I be using. If support is not available currently, will it be available soon.

Thanks for your help in advance.

pcam I played a while ago with Scotty 3.0 for windows (unofficial release can be found here: [L7 ]), and tried some SNMPv3, and I did not find anything missing for what I was doing, but I remember reading that it was not fully implemented (see [L8 ])

vish Thank you Pierre. -Vish


Sunblades and Starpacks

MSH - I've just seen that Larry Virden uses a Sunblade at work with tclkit. I am trying to get a starpack working (My MSEdit) on our sunblade (tcl 8.4.9 with tile7.8) using the tclkits on [L9 ] but when I load tile I get the following message

 source tile07.kit
 package require tile
 couldn't load file "/var/tmp/tclGnaq6o": ld.so.1: tclkit-solaris-sparc849: fatal: libm.so.2: open failed: No such file or directory

do you have a tclkit 8.4.something capable of loading tile.so on a sun, or maybe an explication of what is missing on our machine.

 uname -a
 SunOS cosinus 5.8 Generic_108528-19 sun4u sparc SUNW,Sun-Blade-1000

Thanks in advance

LV 2007 Nov 8

Sorry, I replied earlier this week, but the day's changes appear to have disappeared. Anyway, that error appears, to me, to indicate that some piece of code - perhaps the tile kit - was compiled on Solaris 10 but that you are trying to run it on an older Solaris. I have not built tile, so I don't have code to give you as replacement.

I sure hope this comment doesn't disappear...

MSH - I saw your comment briefly before it disappeared the last time. Thanks for the reply i tried ldd on the kit and the tclkit but neither listed libm.so.2 only libmm.so, I will continue my investigations. P.S. How can I tell if it is a Solaris 9 or 10 ?

LV I'm glad you saw it. I was out sick yesterday and so didn't realize until today that the comment had vanished.

To figure out what sunos you have, use

 $ uname -r
 5.9

which would be SunOS 5.9 (Solaris 9).

MSH Thats right

 $ uname -r
 5.8

I would try 8.5b tclkit which includes tile but it is not yet available for Sun.


Wingdings!

MSH - 30/10 I'm trying to display some symbols from the Wingdings font on a text/message widget using code

 pack [text .t -font {Wingdings 48} -width 17 -height 4]
 .t insert end \x8C\x8D\x8E\x8F\x90\x91\n

this displays the Round 2 4 and 5 but the other symbols are displayed as squares does something else need to be done such as encoding ?

I tried using the code from RS's Webdings animation but he does nothing special to display the characters.


EDIFACT

Is there an EDIFACT tcl module somewhere? I need it to create an XML-interface, so I have to parse and create the messages (starting with INVOIC and ORDERS, but more will follow).


Password Reversal

KK Are you familiar with the "John the Ripper" (JTR) utility?

In UNIX passwords may be stored as a encrypted value. Optionally people use shadow for better security but let's assume that's not the case. Given an encrypted password JTR calculates the unencrypted value by trying all the combinations.

As a trivial and completely made up example:

1. My passwords it the letter "d" 2. UNIX encodes this to some strange value "Uon'92nf3dj" 3. JTR encodes each character in order:

 a = "Jnqpdn92ndo"
 b = "on3#9dm3;g*"
 c = "90gn1)ksn?s"
 d = "Uon'92nf3dj"

4. Bingo I now know the unencrypted password.

I came across a separate utility that can not be mentioned that encrypts values to store in a database. I managed to whip up something that achieves the same thing in TCL although truth be told it's not very fast at all!

My first approach kept an array of ASCII values and when one passed the threshold it ticked up the next one. My second approach kept one value which it then decoded using divide (to find the value of this char) and modulus to find the remainder left for the other values e.g. if we just had a-z then a = 0, z = 26, aa = 27, aZ = 52 etc.

Unfortunately can't paste any code here but I'm interested to see how others would approach this problem. RS See Mapping words to integers.

KK - Yes exactly like I did it, almost down to the minute detail :) My conclusion is that it's far too slow for any password of even modest length.


Client/Server, JSON

Idarac 2 part question here. 1. I have the Server/client apps up and running. If multiple clients are accessing this server app (and it could be in the hundreds) what is the effect on performance as the number of clients builds. Mind you the client will only be connected long enough to check for any new data updates etc. But in the case where a new dataset is available it will have to be uploaded to the client. Is there a maximum number of clients (# sockets) that can be tolerated.

2. Something else I am looking at is having the client actually access the database and retrieving the info using HTTP to request some SQL and get back my db results in JSON.

Anyone know what JSON is? And can someone compare the 2 setups #1 and #2 pros and cons.


SL 22 Oct 2007 - I can't get TEA working. According to "TEA on Windows" autoconf works, but running ./configure under cygwin returns a failure: "configure: error: cannot run /bin/sh ./config.sub". bash(sh) is available and running. What's about this config.sub? Any help appreciated. Answer: config.sub and config.guess where simply missing. I installed automake and copy-paste them from there into the sample-tea-directory. Thanks anyway


Regressing the 8.5 Text Widget

MSH - Now that the 8.5 version has arrived in Beta version I would like to change my development platform over to 8.5, however I use the text widget a lot and I understand that the smooth scrolling is great with images displayed but I would like to be able to still use the old line scrolling. What if any is/are the option(s) to continue using line scrolling with the new text widget ?

MG 18 Oct 2007 - If I'm understanding what you want to do correctly, this would involving changing all the bindings for the text widget that scroll it in some way, and changing the places they use "displaylines" for "lines". That would, I believe, make it scroll the same way 8.4 does. Though that may not be what you mean...

MSH - I was hoping for something simpler than changing all the bindings, for backwards compatibility the text widget that displays only text should be capable of scrolling normally by whole lines without having half a line of text displayed on the top. When the scrollbar sends a yview command I want the view rounded to the nearest line not pixel.

MG Ahh, I see what you mean. I don't think you should have a problem. I'm using an 8.5 text widget in an app (with text only, no embedded images) and it scrolls perfectly - better than an 8.4 widget, because it scrolls by visual (wrapped) lines, rather than internal (unwrapped) lines. The only time I've ever seen it scroll by anything other than a whole line is using the Mousewheel, where it does scroll by pixels, but that's just one binding to change, which isn't such a problem. From a brief experiment on Windows, something like:

  bind Text <MouseWheel> {%W yview scroll [expr {round(%D/40.)}] units}

would probably work. (%D, the delta, seems to always be 120 or -120 on my system, so for me this makes it scroll by 3 lines.)

MSH 18 Oct 2007 - Thats right it works OK but the Scroll bars still send a yview fraction of the full text height so its easy to offset by a half line and then the Mousewheel scrolls by three whole lines still leaving the half line at the top ! I don't understand your reference to wrapped/unwrapped lines, apart from the resizing of the scrollbar holder.

MG Ahh, I see what you mean - in 8.4, when I drag the slider on a scrollbar, the text widget only moves by whole lines. In 8.5, it moves smoothly, which means it can display fractions of lines. You'd need to use a wrapper proc to make it scroll only by whole lines, I think. This seems to work reasonably well, though it's only very minimally tested...

  proc foop {widget args} {
    $widget yview {*}$args
    $widget see @0,0
  }
  pack [text .t -yscrollcommand [list .s set] -wrap word] -expand 1 -fill both -side left
  pack [scrollbar .s -command [list foop .t]] -side left -fill y
  .t insert end [string repeat "[string repeat "This is a test." 15]\n" 100]

Working with Databases

Idarac Thanx everyone for all your help. I now have 2 apps running one on the client side one on the server side and the client can connect on a socket. The next step is to try and read different database formats. What is available for connecting and working with different database formats (MySql, Sql Server, Access.SqlLite)?

MG There are a lot of options available, depending to some extent on which platforms your code is running and which kinds of db you want to access. I'd recommend just doing a search [L10 ] for SQL and taking a look at some of the pages that come up. Over the years, I think I've used FBSQL, mysqltcl, TclODBC, SQLite, and probably a few others that I forget...


Deployment

Idarac Can someone give me a blurb about TCL deployment with or without using the Tcl Dev Kit. Deployment to a server as opposed to a client. Does TCL have to be installed on both for my code to run?

MG You'll need to have Tcl installed in some form on every machine you want to run Tcl code on. As far as the best way to do that... Having never used Tcl Dev Kit, I'd recommend looking into Tclkit for deployment, at least for the client side - you can use Tclkit/Starkit/Starpacks to produce single-file executables for a range of platforms with relative ease. Plenty of info about it on their respective pages.

Idarac So these single-file executables have everything including the TCL to run the application. Nothing else is required. No TCL install? That is correct. You end up with a single executable file that is entirely self-contained.

For the server side, it's probably easier not to wrap it into a single-file exec, but retain access to the plain Tcl file for easier editing/viewing of the code, I would think.

peterc Tcl Dev Kit's tclapp produces starpacks (and goes the extra mile by wrapping those starpacks inside Application Bundles for you when producing apps for the Mac platform). The big selling points: starpack code obfuscation, ease of use and top notch support when you need it.

The big selling point for starpacks in general: you're able to handle the end-user a single executible file. It doesn't matter which version of Tcl (if any) they already have installed, since the Tcl and packages you're using are self-contained within your executible's own internal virtual filesystem and guaranteed to be the ones you've tested against.


Pros and Cons of Activestate

Idarac Any one here familiar with Activestate? We are considering it for our development environment. We will first be developing for the Wondows OS then porting the app to Linus and Mac OS. My other question is deployment of my apps?

Pros and Cons of Activestate anyone?

LV I've dealt with the Activestate company off and on for a few years. I don't see any cons of the company.

I like to encourage Tcl developers to look into the Tcl Dev Kit and to consider purchasing it when possible. I love the static code analyzer. There is a nice debugger as well. And of course, the free distributions of ActiveTcl are wonderful when used in conjunction with TDK's single file executable creator, which then are easily used for deployment.


Beyond regsub

LV 2007 Oct 1 Goal: Using regsub, remove a delimiter (provided in a string), and to upper case the next alphabetic character, from an arbitrary string.

Generally speaking, you can't use regexp (or regsub) to up-case characters. Not without a big, explicit expression that explicitly replaces a with A, b with B, c with C, etc.

Also, the problem is ill-defined. When you say "to upper case the next alphabetic character", what do you mean? If there is a delimiter followed by N non-alphanumerics and then a alphanumeric, do you still uppercase that first alphanumeric? Or, does the alphanumeric have to immediately follow the delimiter?

Delimiters are:

 -
 %
 *
 $
 @
 !
 #
 &
 ^
 _
 ,
 .
 ;
 :

and a space.

I have tried:

 set delimiters {[-|%|*|$|@|!|#|&|^|_|,|.|;|:|\ ])(\w)}

 set test [list {thaddeus Cooper} \
               {%idiotic_Field*name} \
               {hey#hey#Hey,hello_world} \
               {this#is_a_test_of_the-emergency-broadcast-system}]

 foreach item $test {
   regsub -all -- $delimiters $item \2 item1
   puts $item1
 }

Ideally, what would end up being produced would be:

 ThaddeusCooper
 IdioticFieldName
 HeyHeyHeyHelloWorld
 ThisIsATestOfTheEmergencyBroadcastSystem

but what is happening is that the letter after the delimiter is being deleted, in some but not all cases.

 thaddeusooper
 dioticieldame
 heyeyeyelloorld
 thissestfhemergencyroadcastystem

Any suggestions?

  foreach item $test {
      regsub -all -- {[^[:alnum:]]*([[:alnum:]]+)} $item {[string totitle \1]} script
      puts [subst $script]
  }
  # -- groks

Is speed an issue? If not, one solution is to make two passes. First, convert all delimiters to the same character. For example, convert all delimiters to "-". Second, pass the data through string map with a map that looks like:

    set map [list -a A -b B -c C -d D ...]

Thus, "%idiotic_Field*name" first becomes "-idiotic-Field-name" and then "IdioticFieldName"

slebetman If you don't insist on using a regexp based solution then it's pretty simple:

  set delimiters {-%*$@!#&^_,.;: }
  set test [list {thaddeus Cooper} \
                 {%idiotic_Field*name} \
                 {hey#hey#Hey,hello_world} \
                 {this#is_a_test_of_the-emergency-broadcast-system}]

  foreach item $test {
    set result ""
    foreach word [split $item $delimiters] {
      append result [string totitle $word]
    }
    puts $result
  }

Should produce the result you're after.


Rendering SQLite Query Results

tb 21 Sep 2007 - Which table widget suits sqlite queries best?

JC 23 Sep 2007 - I'm not sure one would be better suited for a particular SQL database vs. another, however, I have very much enjoyed using tablelist. It seems well suited to any database. It gives you sorting, stripping, inline editing, the ability to hide columns (say, the first one is your internal record id), etc...

tb: Ok, thanks for pointing to tablelist. I was asking, because there might arise problems, when trying to associate a queries result set to the tables own data type and was wondering, whether there are known issues.


Communicating with QT

Idarac Here is a new twist to my app. I have been asked if a TCL app can somehow communicate with a QT app. Any takers out there? Do you mean an unmodified QT app, or one that you can modify? Certainly tk and QT apps can communicate via sockets.

escargo - Well, are they on the same machine or not? Does one start the other? Pipes or sockets are probably workable solutions.

Idarac Initially they will sit side by side. But they may or may not in the future. The QT app will start up and ask the TCL app to go and check if there is a new datasource (XML) on the server waiting to be downloaded. The TCL checks and if yes then downloads the file and sends a message to the QT app saying yes there is a new file and it is called "Newfile.xml"

escargo - I would say sockets are probably the most workable solution. There's an implication that the Tcl app can determine of a datasource is new or not. Can it tell because a datasource exists or does it need to look for sources dated after a supplied date? What restrictions are there on where the Tcl app can write? I presume it needs to hand a fully qualified local pathname to the QT app. And if the Tcl app and QT app are not on the same machine, then can the QT app handle a URI so that it can fetch the payload itself?

Idarac Depending on the capabilities of TCL we can either use the date stamp on the datasource file or we can use a naming convention that includes the date of revision. SO the TCL app knows where to download and the QT knows where to locate it. The restrictions for the TCL app to write will vary depending on the site so I am thinking that the only guaranteed location would be the location of the QT app. So the TCL should drop the file into the QT app location. If the location is different that would be stored somewhere on the server.

Does any one have any code samples of a TCL app communicating with a QT app?

MG I have no familiarity with QT, but from the Tcl point of view, you use a server socket to listen for connections. You can have it listen for any particular string(s) sent from the QT app, and have it do whatever is necessary and then reply with puts (and the QT app would obviously need to be set up to connect to the Tcl app on whatever host/port it's listening on, send the appropriate commands and parse the response correctly).

Idarac Can I ask what is the difference between sockets and using RPC or http in this situation?

MG I've never used RPC, but I believe this applies to it, as well as http: http does use socket. The socket command (along with gets, puts, etc) is a fairly low-level command for TCP communication. It just creates a server that listens for TCP connections (or connects to an already-listening server, depending on how you use it); you then just implement http by sending particular strings through the connection (though there are packages which send and listen for the correct strings already, to save you having to implement it all from scratch). Using http is certainly a viable option, but if you only want to perform one (or two) very basic operation, it could be overkill. Then again, using http from the start could make your system easier to expand later, and would save you having to create and document your own protocol.

escargo 20 Sep 2007 - Remote Procedure Call (RPC) is a kind of message passing and remote invocation. The idea is for cooperating processes, potentially on different machines, to make procedure calls and return results. HTTP is a higher-level protocol (on top of TCP/IP) for clients to use to fetch text and images from servers.

Depending on where the server with the new data is, where the Tcl program is, and where the QT program is, life can get more or less complicated. If all three are on different systems, then the server has to make available to the Tcl program that there's new data available (that's a networking issue between the Tcl program and the server). It's a lot easier if the Tcl program is running on the server where the new data is.

For the QT program side, if you are able to influence its construction, and you can use software written using the MIT license, then if you incorporate libcurl [L11 ] you could use HTTP to fetch data from a minimal Tcl web server (my favorites being dustmote and castle, but there are others).

In some respects that's overkill, but there are many simpler choices as well. Check out Category Interprocess Communication.

Idarac Hmmm, not a bad idea putting the TCL app right on the server. The TCL app is acting as a server app anyway listening for the QT app. Instead of listening for one app it would have to listen for many QT apps. That does cut out one step of the process. QT having to query the TCL app which in turns has to query the server. That would also help in the distribution to our remote sites, it would always guarantee an up to date TCL app without having to do updates. Am I correct in assuming that the TCL app could listen for more than one app on the same port?

escargo - Many of the sample servers here on the wiki handle multiple clients on the same port. Depending on the complexity of handling the queries, the communication between the client and server can almost be the client sending "Send me the latest update older than date X" with a response of either the update or an empty response.

Your main limitation is going to be the QT application. The Tcl side is very flexible. (That is, there are many possible choices.)


Client/Server Security

Idarac Thanx LV for your help in getting me underway. The TCL program will exist on various machines external to our server. The operating system will also vary on these machines, the program will have to run on Windows, Linux and Mac/OS.

The TCL program will poll our server on startup and if an upgrade exists, the query to the server will return the new XML filename. This is the trigger for a download of the XML file. The file (XML) will be downloaded into a local datasource (to be determined, SQLite?).

What security concerns need to be taken into account?

LV Is the data sensitive? What would happen if a hacker attempted to provide you some other file other than what you expected? Take a look at OTP to see if perhaps some kind of authentication is in order.

Based on my requirements can you suggest file protocols, best option?

LV I would suggest that you make use of something very simple - perhaps like http, because that is a pretty simple thing to implement, with basic functionality provided in tcl packages.

When querying the server what are some options? Database format, csv, xml?

LV Good question - hopefully someone else reading will have some experience in here. Take a look at things like Tequila to see how others have done things like this.


Better Bindings

LV Okay, a co-worker is writing his first Tk application on Windows XP. He has some code which creates a listbox called .choices, grids it into visibility, then sets a ButtonRelease binding like

 bind <ButtonRelease-1 {MyProc [.choices curselection]}

Within MyProc, he takes the index passed (yuck - index numbers. Fortunately, today, he only has 2 bindings and he knows what each one means. Otherwise, whew, what a mess) and then takes one of two actions, based on which one is passed.

He then wants to make the .choices widget go away. So he added a call to destroy, with the listbox's name. What he gets back is an error message saying

 invalid command name ".choices"
 invalid command name ".choices"
    while executing
 ".choices activate @18,8"
    (command bound to event)

where it seems, to me, that the numbers after activate vary from time to time.

We don't know what this error is trying to say. Anyone willing to share a clue?

Zarutian 17. september 2007: I guess that the bind command in his script binds the eventhandler to the toplevel window of the application. Because of that, when the left mouse button in depressed inside that toplevel window the eventhandler is invoked and because destroy deleted the listbox and the handle to it (which happens to be also an Tcl command). so bind the event to the listbox itself.

LV Here's some code which replicates the problem simply:

 $ cat lbt.tk
 package require Tk

 set listvals [list]
 proc execute {args} {
        if { [string match [info commands console] "console"] } {
                console show
        }
        puts "execute received arguments of $args"
        destroy .c
 }

 listbox .c -listvariable listvals
 bind .c <ButtonRelease-1> {execute [.c curselection]}
 grid .c

 lappend listvals Alpha
 lappend listvals Beta

 $

Run the above code, then click on either of the list elements. What I see is an application error dialog that says

 Error: invalid command name ".c"

and, when I select Details>> I see this additional info

 invalid command name ".c"
 invalid command name ".c"
    while executing
 ".c activate @59,16"
    (command bound to event)

So, what would the appropriate change be to the sample code?

LV Well, in thinking about the specific message, I began to wonder if the problem was that the original binding for ButtonRelease-1 was firing after the widget was destroyed. So, I changed the binding to

 bind .c <ButtonRelease-1> {execute [.c curselection]; break}

and the error message is now gone.

There is an empty frame left, in my example. I will have to see whether that is the case for the developer or not. Thank you everyone for your help!


Getting Updates

Idarac Thanx LV and MG for your excellent advice and assistance. You have given me is a "great" kick in the pants to get started.

Idarac Holy Man am I getting turned around here. I have been charged with developing a TCL app which queries a Server for a new update and if it is available download it. The download would be in CSV or XML format. Can anyone give me a bit of a conceptually of how this works. Do I have to develop a Server side app and a client side app. Anyone have any examples I could look at?

LV Well, the first thing you need to know is more about the requirements. For instance, are you responsible to create a program that generates the update? Is the machine on which the update resides a machine within your company/project's domain or is it external to your company? Is the file accessible via http, ftp, NFS, Samba, or some other protocol, or do you have to invent that access? If you have to invent it, are there external restrictions as to what you can use? Is mere presence of the file a sufficent event to trigger a download, or does it need to be new as well? How frequently are the updates needed - as soon as the file is updated, or can you just poll for presence once a year/month/week/day/hour/minute? What security concerns need to be taken into account?

Once you know where the file is, what protocol you have available for access, and some of these other factors, then you should have a better idea what you are going to need. I recommend that, if you get to choose the answers to these questions (as well as any others you might dream up), that you choose as simple a solution as is workable with the rest of the requirements. The more complex a setup, the more complex the software needs to be. Also, if possible, select solutions for which there are already solutions, if possible. For instance, if you get to choose the transfer protocol, use the simplest and most common you can use. Use NFS or Samba for internal sites, for instance, and you won't have much else to write.

Also, try to think outside the box. For instance, if this data is coming from a database, then do you actually need it in an external file, or is there perhaps some kind of status field or something in the database that you could use to extract the data directly, saving you a lot of parsing,etc.

MG offers a very brief and untested example off the top of his head (using separate client and server apps), as it's far more fun than doing real work. You're likely looking for something a lot more refined, but hopefully this may give you some ideas.

 # Server
 proc serve {channel addr port} {
   variable conns
   fconfigure $channel -translation lf -buffering line
   set conns($channel,addr) $addr
   set conns($channel,port) $port
   set conns($channel,state) 0
   fileevent $channel readable [list readFrom $channel]
 }
 proc readfrom {channel} {
   variable conns

   if { [eof $channel] } {
        abort $channel
        return;
      }

   set line [gets $channel]
   set state $conns($channel,state)
   if { $state == 0 } {
        if { $line != "date 1" } {
             abort $channel
             return;
           }
        puts $channel [file mtime $::file]
        incr conns($channel,state)
      } elseif { $state == 1 } {
        if { $line != "file 1" } {
             abort $channel
             return;
           } else {
             puts $channel [file size $::file]
             fconfigure $channel -translation binary
             set fid [open $::file r]
             puts $channel [read $fid]
             close $fid
             abort $channel
           }
      }
  }
 proc abort {channel} {
   variable conns

   catch {close $channel}
   array unset conns $channel,*
 }
 set file "./somefile.txt"
 set port 12345
 set server [socket -server serve $port]


 # Client
 proc getFile {server port} {
  variable contents
  variable size
  if { [catch {socket $server $port} conn] } {
       puts stderr "Unable to connect: $conn"
       exit;
     }
  fconfigure $fid -translation lf -buffering line
  puts $conn "date 1"
  gets $fid date
  if { ![string is integer -strict $date] } {
       close $conn
       puts stderr "Unknown response to 'date' command"
       exit;
     }
  if { $date <= [file mtime $::file] } {
       puts $conn "file 0"
       close $conn
       puts "No new file available"
       exit
     }
  puts $conn "file 1"
  gets $conn size
  if { ![string is integer -strict $size] || $size == 0 } {
       close $conn
       puts stderr "Unknown response to 'file' command"
       exit;
     }
  fconfigure $conn -translation binary
  set contents ""
  fileevent readable $conn [list readFile $conn]

 }
 proc readFile {conn} {
   variable contents
   variable size
   if { [eof $conn] } {
        catch {fileevent readable $conn {}}
        catch {close $conn}
        if { [string bytelength $contents] != $size } {
             puts stderr "Download incorrect; wanted $size, got [string bytelength $contents]"
             exit;
           }
        set fid [open $::file w]
        puts $fid $contents
        close $fid
        puts "Done!"
        exit;
      }
    set str [read $conn 10]
    append contents $str
 }
 set file "./download.txt"
 getFile localhost 12345


Formatting Floats

FH (12 september 2007) Easy (for you).

I have an integer in format 1234500 and a number of decimal places which should be applied. My problem is that the format string which i use removes additional zeroes. Example 1234500 with 2 decimal places should become 12345.00, but I always get 12345.0

MJ - Without seeing your format string, there is no way to be sure what is going wrong, but try:

 % format %.2f [expr {1234500/100.}]
 12345.00

FH Works. Did not use %f.


Stressing Switches with Multiple FTP Transfers

CJL (11 september 2007) - I'm putting together a little script to do multiple simultaneous ftp transfers (in both directions) as a way of stressing a switch, and I'm trying to use 'package require ftp' but am having problems with using it asynchronously. I want the bulk transfers to happen asynchronously (as a result of specifying '-command'), and simultaneously, making use of a callback via the '-progress' argument to keep track of what's happening. However, that makes setting up the connection awkward as any one call into the package, such as the initial '::ftp::Open', can cause multiple calls to the '-command' callback, meaning there doesn't seem to be any indication as to when the first command has completed and it's safe to proceed to the next command (i.e. '::ftp::Cd', '::ftp::Type' and then '::ftp::Get' in my case). I can find nothing in the docs to explain how to deal with this situation.

Lars H, quick suggestion: Have you considered adding an argument in the callbacks (a callback should allow a command prefix, not just a procedure name) which lets you keep track of what it was a callback for?

CJL - The callbacks already take a single argument to identify which server connection the particular call is associated with. Adding a 'reason' argument doesn't help identify when the 'reason' is complete. e.g. ::ftp::Open calls the callback three times, once each for 'user', 'password' and a non-fatal error about not being able to set the type (I don't remember the exact wording). For now, I've hardcoded an expected-number-of-responses value for each operation (Open, Cd, Filesize, etc...), but that will break in the event that the number of responses changes (e.g. if connecting to a different server makes the type setting error go away).

Lars H: So the problem is not with multiple connections as such, but with at all using the asynchronous mode of the ftp package. The documentation in this area is indeed insufficient (mentions there are keywords for the operations completed, but not which they are or what they mean -- could be reason to file a bug report against the documentation).

From looking at the implementation, it seems you're supposed to get a connect keyword when the connection is ready (either from the connect or connect_last branch of ::ftp::StateHandler), but if that doesn't happen then something seems strange. DEBUGging is probably in order to see what is going on in the connection to the server. Also, have you tried specifying -mode in the call to ftp::Open, since the default (which seems to be empty) produces an error?

CJL Yes, it's asynchronous mode that's causing me problems - I only mentioned the multiple simultaneous connections as justification for using async. '-mode' is supposed to default to 'active'. Explicitly setting it to either 'active' or 'passive' does not prevent the error (''error setting type""'). Stepping through the sequence of operations to initiate a transfer reveals that I do get a 'connect' response, but strangely, it's the second response to a 'cd' command (?!?!!?). Thanks for looking into this, but I'm afraid my cludge will have to do until I find more time to revisit the problem.

Lars H: Regarding -mode, I was thinking -type (ascii/binary), but there doesn't seem to be an ftp::Open option for this. Since it insists on setting the type, but doesn't have neither ascii nor binary as defeault, it seems it chooses "local mode" [L12 ] instead. Upon getting an error on this (which it ought to, since the TYPE command sent lacks a parameter!), it will not continue to report the connection completed, and indeed the state that is supposed to do this may sit in the queue until a cd command.

Conclusion: This is a bug in the ftp package. You might be able to work around it by doing

  set ::ftp::ftp${s}(Type) ascii

immediately after the ftp::Open. The $s is the serial number returned by ftp::Open.


Iwidget Date Format

MHo Just wondering if it's easily possible to change the date format of the Iwidgets. If not, these date widgets, and in turn the whole Iwidgets, are nearly unusable for german users, e.g.

LV I'm not an iwidgets expert. However, I don't see information in the iwidgets doc for the 3 date related man pages, that would indicate that these widgets had been internationalized in terms of things like date format, etc.

I suggest that you visit the widget set's sf.net web page and submit a feature request for this. However, it may be quite some time unless you want to make it happen sooner. For that, I suggest learning enough about itcl and iwidgets to write the code you need, or, if that isn't doable for some reason, then I suggest that you ask for help, understanding that if you need it very badly, you might very well have to pay someone to write the code you need.

MHo: Thanks! Meanwhile, I found a link to some patched versions of some files, where the date format is 'hard-replaced'. Ok, not the best but I will try it and communicate a change request later.


Iwidget Component Help

MHo Another one... Why does the following command has no visible effect? (new to Iwidgets, sorry):

 .mw component help configure -text "hmmmmm"

This don't work, either:

 [.mw component help] configure -text "hmmmmm"

But this does:

 set [.mw component help cget -textvariable] "hmmmm"

(.mw is a mainwindow with a help component)


Working with SQLite

Hello, Newbie TCLer here. I have been charged to develop a new app using TCL/TK using SQLite as the database. Anybody here have any experience with this? We also want to be able to check a websit on program startup to see if a new licence exists and if so download it and apply it to the program. What does Activestate TCL offer as a dewvelopment environment? What would be the way to go for network communications?

Anybody help?

Randy

MG Tcl's socket command is very simple to use for basic communications. There's also the http package included with ActiveTcl which can be used for downloading webpages and checking the page content/response codes, etc. I've never used SQLite myself, but I'm pretty sure there are some examples on the Wiki here.


Managing Script Safety with Untrusted Code

fpgabuilder Folks, sorry if I am not posting this according to the convention here. Please let me know if so. I am thinking of using tcl to build an application that will

  1. receive a tcl script over the network in a folder allocated to a particular sender
  2. execute the script from this folder
  3. return the result back to the sender

Now I can see a lot of resources to setup the communication. What I do not know is how can I prevent accidental or rogue script from causing damage to the files outside of the folder from which it is supposed to execute. Is this even possible? Any pointers would be greatly appreciated.

TIA

Lars H: Have a look at safe interps. They can't stop the script from crashing, but they can stop the script from accessing the file system in unwanted ways.

(answered and moved questions moved down page)


Generating Words

pcam I am trying to generate all possible words made of the extended ASCII char range (0-255). Ultimately I would like to call a function that would generate all such words given a maximum word length. I suppose the best way would be to return a list of lists, with the first list being for words of 1 ASCII char etc... My question is why when I make a word using format I cannot store it (but can print it) in a list? I must be missing very simple, I guess.

   proc ascii_words {} {
      for {set i 0} {$i<256} {incr i} {lappend lwords [format "%c" $i]}
      puts $lwords
   }

RS: Just return the result:

    proc ascii_words {} {
      for {set i 0} {$i<256} {incr i} {lappend lwords [format "%c" $i]}
      return $lwords
   }

Then call it:

 set chars [ascii_words]

Get all two-letter words like this:

 foreach i $chars {foreach j $chars {lappend words $i$j}}

and so on, till you reached your maximum length.

pcam Thanks for your help. Surely I am having a bad day as this does not work either. The list is blank. To be sure I have re-installed ActiveState 8.5.b8. Help please ! - RS: We cannot remotely debug code that we don't even see. Can you post your code that does not work?

pcam What does not work is simply the code you posted. I guess you must have tested, hence I have though of a tcl install issue.

  proc ascii_words {} {
    for {set i 0} {$i<256} {incr i} {lappend lwords [format "%c" $i]}
    return $lwords
  }
  set chars [ascii_words]
  puts $chars

What surprises me is why the output of format is different ? I always thought everything is a string in tcl. For sure replacing format "%c" $i with $i and we have a list returned by our proc.

GWM The list is empty because the character 0 terminates a string in C, and this is the first character in the list. Try

  proc ascii_words {} {
  for {set i 1}  {$i<256} {incr i} {lappend lwords [format "%c" $i]}
    return $lwords
  }
  set chars [ascii_words]
  puts $chars

pcam Doh! Thanks a lot, this had to have a simple explaination.

GWM Further experimentation shows that the original chars (from 0 to 256) has string length $chars = 535 and llength $chars is 256, so the characters have been constructed correctly - it is only when you try to use puts to print the result that the NULL character terminates the puts. The following:

  puts [string range $chars 2 end] 

will show the expected list of characters. On my machine, however, starting RS's

 foreach i $chars {foreach j $chars {lappend words $i$j}}

results in an extremely long (possibly non-terminating) operation.


Tristate Interaction?

MG Is there any way with Tk 8.5's checkbutton to get the "tristate" mode, other than manually setting the -variable to the value given in -tristatevalue? It seems that clicking only toggles between "on" and "off", which makes it rather limited for some of the uses of a tristate checkbutton (ie, letting the user toggle between "This must be on", "this must be off", and "I don't care about this").

DKF: No. I'm not aware of any usecase that requires that behaviour either.


From BEN00 To all that helped with the button size question. The final answer is that nothing changed the size of the buttons untill I modified some of the configuration settings for Attachmate KEA!X. Once I changed the settings, the button(and window) size got smaller like I wanted. Just though I would pass this along in case someone else has the same problem. Thank you for your help!


Itcl Class Variables

AdrianP asks:

I'm trying to learn about incr tcl, and it's mostly going well despite the lack of good tutorials online. I do have one question, though, about some behaviour that is different from other object-oriented languages I have used before. Consider the following code, a very very simplified version of what I am trying to do:

  package require Itcl

  itcl::class Foo {
          public method change_variable {vname vvalue} {
                  set $vname $vvalue
          }
  }

  itcl::class Bar {
          inherit Foo

          public variable baz 5

          public method new_change_variable {vname vvalue} {
                  set $vname $vvalue
          }

          constructor {} {}
  }

  set obj [Bar #auto]
  puts "baz: [$obj configure -baz]"
  $obj change_variable baz 7
  puts "baz: [$obj configure -baz]"
  $obj new_change_variable baz 7
  puts "baz: [$obj configure -baz]"

At the moment, this code returns:

  baz: -baz 5 5
  baz: -baz 5 5
  baz: -baz 5 7

In other words, the inherited "change_variable" method is unable to modify the Bar class's variables -- and yet copy-pasting the exact same proc with a different name into the Bar class suddenly works. I would like the first call to change_variable to also work. Since in my actual application, I have many derived classes all inheriting from the same class, I would obviously prefer to define the proc only once in the base class rather than reimplimenting the exact same function each time. How can I make this work? Thanks in advance! :)

PS: I know that making setter/getter procs would solve this problem, but I don't want to do that mainly because I want this to work with private variables also, for which I do not want there to be accessors.

GWM try in Foo:

         public method change_variable {vname vvalue} {
                  $this configure -$vname $vvalue
          }

the "$this" variable tells the method to operate in whatever its highest class is. The configure -varname can also set a value, but can only access public variables. Use of $this is often required to force itcl to call a routine which has been superceded in a derived class. If you only need to set the value then all you need is a set$vname method to set any variable. I often use some included tcl in a class to create a list of variables and automatically generate the set/get methods:

  itcl::class BarBar {
          inherit Foo
         foreach {vn val} {bar 5 barf 6} {
          protected variable $vn $val
          public method set$vn {v} [subst -nocommand {set $vn \$v}]
          public method get$vn {} [subst -nocommand {return $$vn }]
          }

          constructor {} {}
  }
  set o [BarBar #auto]
  $o getbar ;# returns 5
  $o getbarf ;# returns 6

Upgrading with DLLs

DocTec asks:

I have inherited a piece of software written in Tcl that uses extensions, and I'm having trouble upgrading the version of Tcl it runs on. The extensions are .dll files for Windows, and I think they're written in C, but I don't have source for them.

Everything works fine under Tcl 7.6. From tclsh or wish I can run "load magsup.dll magsup" and the program works perfectly. If I'm using Tcl 8.0 or higher, then wish dies when it tries to load the dll.

I presume this means that there was some major change in the way that extensions work from v7.6 to v8.x. Is there any way to use these old libraries under 8.x? I can largely replace them with pure Tcl code if I upgrade to 8.x, but there's no way I can do it all at once.

Thanks, all.

LV No, there really isn't a way to do this. The 7.6 to 8.0 code change was pretty dramatic ; since 7.6, unicode is supported, threadedness, big numbers, etc. Interfaces depended on by the extensions have changed signature, or disappeared altogether, etc.

Looks like you will need to do one of two things. Either work on rewriting all the extensions before moving forward, or segmenting your program so that when you need the old extension functionality, you exec a tcl 7.6 program which makes use of the extension and returns the value needed. You could make this a bit easier by writing a series of procs that correspond to the commands. Each proc would be a "wrapper" that would exec some program (doesn't have to be a separate program for each command - but at the very least, has to be a dispatcher type program that takes as an arguments the name of the command to run as well as a serialization of the original arguments . Depending on the complexity of the arguments, this could be harder than just rewriting the commands...

DocTec: Thanks, it's good to at least know for sure that things are incompatible. I might try the wrapping approach, though it'll be tricky because several of the extensions are reading data from files and drawing it on a canvas. I'll have to ponder which is less painful: wrapping it all (ugh) or rewriting everything in parallel (double ugh)...


Button Sizes

From BEN00 In response to your question about about the size of the buttons, perhaps the diagram below will help explain what I am looking for. Current:

        +------------------------------------------------------+
        | +-----------------------+ +------------------------+ |
        | |                       | |                        | |
        | |         OK            | |        CANCEL          | |
        | |                       | |                        | |
        | +-----------------------+ +------------------------+ |
        +------------------------------------------------------+

Desird:

        +------------------------------------------------------+
        |                                                      |
        |          +--------+           +---------+            |
        |          |   OK   |           | CANCEL  |            |
        |          +--------+           +---------+            |
        |                                                      |
        +------------------------------------------------------+

MJ - How does the following look to you?

         wm title . "Logon Aid"
         frame .f1
         frame .f2 -pady 4
         pack .f1 -fill both -expand 1
         pack .f2 -fill both -expand 1
         label .f1.lusr -text userid
         entry .f1.eusr -textvariable userid -relief sunken
         grid .f1.lusr .f1.eusr -sticky ew
         label .f1.lpw -text passwd
         entry .f1.epw -show "*" -textvariable passwd -relief sunken
         grid .f1.lpw .f1.epw -sticky ew
         button .f2.ok  -text "OK" -command {exec touch frog} -width 8
         button .f2.cn  -text "CANCEL" -command {destroy .} -width 8
         grid .f2.ok .f2.cn
         grid columnconfigure .f2 "0 1" -weight 1
         wm resizable . 0 0


MG I suspect the answer to this is 'no', but is there any way I'm not aware of to see how long a timed after has left until it runs?

DKF: No. (Or at least not currently.)


Computer Discovery

From SpaceManiac I have created a network chat program for personal use and am wondering... How do I discover computers? So far it asks for a hostname and a port #, but I want to make a graphical list of potential connections, like in multiplayer computer games. I use the socket command to connect between computers. Please help!

MG You'd need to have a server that all clients connect to when they want to play online. The server would keep a list of connected players (clients), and whenever a new client connects it would a) show them the list, b) notify everyone on the list that they've joined, and c) add them to the list. (And likewise, when they disconnect/close the program, remove them, and notify everyone else they've left). I believe that's the way other games work which use something like 'Gamespy Arcade'. But letting people enter an ip address to play against their friends without going through the server is another option many games employ (where each client listens on a particular port for other connections, and you need to know the friend's ip to connect).

SpaceManiac Thanks! Tons of multiplayer games i have say something like that, like Civilizations III has a GameSpy Arcade button. I've never clicked it though.

CJL adds: If you're only interested in machines on the same LAN, TclUDP can be used to discover other machines, without needing a server


Button Sizes

From BEN00 I am creating a simple logon interface screen where a login id and password are entered and there are two buttons, one for "OK" and the other for "Cancel". I have been able to successfully code the script so that the screen appears, however, I can not change the size of the buttons. Currently the buttons take up the entire last row. I want the buttons to be about 1/5 the size of the row. I have been able to make the buttons bigger with the -width statement but can not make them smaller. I am a beginner TCL'r and am working on a very limited knowladge base. Can anyone help? Below is what I've coded so far:

         wm title . "Logon Aid"
         wm resizable . 0 0
         label .lusr -text userid -anchor w
         entry .eusr -textvariable userid -relief sunken
         grid .lusr .eusr
         label .lpw -text passwd -anchor w
         entry .epw -show "*" -textvariable passwd -relief sunken
         grid .lpw .epw
         button .ok -width 4 -text "OK" -command {exec touch frog}
         button .cn -width 4 -text "CANCEL" -command {destroy .}
         pack .ok -side left
         pack .cn -side right
         grid .ok .cn

I don't understand the question. You say you want smaller buttons and then talk about them taking up the whole row. When I run the code the buttons are as small as they can be to fit the text. Do you really want smaller buttons, or just want them arranged differently on screen?

You can get smaller buttons by using a smaller font (using the -font) option, but I don't think that's what you really want

MJ - The main problem here is that you are using grid and pack in the same container, don't do that, you are lucky your app doesn't freeze up. Combining different geometry managers in the same container is a bad idea. For another implementation of a login box see A little login dialog.


Working with Text Tags

MG I have a text widget (Tk 8.5) which contains many pieces of text with the tag 'weblink', configured something like this:

  text .t
  .t tag configure weblink -foreground blue -underline 1
  .t tag bind weblink <Enter> [list .t configure -cursor hand2]
  .t tag bind weblink <Leave> [list .t configure -cursor {}]
  .t tag bind weblink <Button-1> [list clicky .t]

(The text with the tag is a URL.) I'm trying to make my 'clicky' proc figure out what the string was that was clicked on, so I can launch that URL. At the moment I have:

  proc clicky {t} {
    set current [$t index current]
    foreach {start end} [$t tag ranges weblink] {
       if { [$t compare $start <= $current] && [$t compare $end >= $current] } {
            launchWebPage [$t get $start $end]
            return;
          }
    }
    bell -displayof $t
 }

but there could potentially be thousands of URLs in the text, and this seems an over-worked way to do it. Is there something simpler than iterating through every range that I'm missing?

Lars H: How about

  $t tag prevrange weblink current

?

MG I tried that and had a problem with it, but didn't spot what it was at the ungodly hour I was doing it: prevrange only returns a range starting before the index given, so if you click the first character with the tag it fails. The solution seems to be to use "current + 1 char" instead. Thanks, Lars (and Elliot, who emailed me) for your help!


Encoding Names

MG (Posted this on the encoding page before, but moved it here in the hopes more people would see it.) I've never really looked at encodings before, and just started doing so for the first time while trying to hack something into a client app. The problem I've just run into is that the server is using the encoding name "iso-8859-1" (which seems to be the correct IANA name), while Tcl calls it "iso8859-1" (without the first hyphen). Is there any reason for this? Or any simple (but correct) way around it? (My immediate thought was to try matching against the Tcl encoding names with the first hyphen edited out, if the encoding can't be found - definately simple, but also definately not correct...) Any help would be greatly appreciated. Thanks.

LV I saw your question on the other page - I just have no idea what to tell you. I've seen all sorts of variations on the names. I believe the name that Tcl is using is the name that is used on the unicode.org web site. I suggest popping over to the TCT mailing list and asking the experts there.

MG will do that, thanks.


Embedding

2007-07-03 dag: Question about embeddable Tcl interpreter (anything recent?)

I'm about to attempt to create a Tcl library to be used in an embedded device for testing and development (it will not be in the shipping product). There is no OS as such, just a home grown real-time executive. Because of safety and real-time concerns, there is no malloc(), free(), or sbrk(), and so on. There is multi-tasking (cyclic and pre-emptive). I'm envisioning a library built from the Tcl sources where the interpreter start-up routine takes a structure that has (at least) the following elements:

  • A pointer to a region of memory to be used as the pool for Tcl allocation
  • The size of the above region of memory
  • A pointer to the get character routine to be used on the console or the aux port (blocking)
  • A pointer to the get character routine to be used on the console or the aux port (non-blocking)
  • A pointer to the put character routine to be used on the console or the aux port
  • A pointer to the put string routine to be used on the console or aux port
  • A pointer to an extension init routine that creates any application specific extensions
  • A pointer to a nul-terminated (should it be counted instead) init script (tcl)
  • A pointer to a routine called when the interpreter is idle
  • A pointer to a routine called at the end of each event loop cycle
  • A pointer to a sleep routine (microseconds)

It is not intended that this return until an "exit" command is interpreted in the outer-most level. All system specifics, such as manipulating the hardware, are extensions that are added by the call to the extension init routine. In the base, there is no fopen(), fclose(), etc.

What I want to know is whether anyone has done this with a recent Tcl already. I found a Tcl 6.7 project, but I'd rather have something a bit more recent. It doesn't need to be the cutting edge, and there will be no Tk (as there is no display, just an RS-232 port or two). If nobody else has done this, I'll do it (or at least try to do it) and post the results. I'd rather not re-invent the wheel, however. I'm doing this on my own (my project is not asking for it) because it will make my life easier on my current project, but I can see this being a generally useful library to have, as it can be embedded in stand-alone apps and hosted apps alike. Various options could include the networking stuff for environments that provide an IP stack or file I/O, but the basic minimal build assumes none of these. I think that it might help the adoption of Tcl in embedded devices to have this available.

Thanks for your attention.


Making a Starkit

tb 2007-05-18 - Hello, I'm searching for a short walk through of a programmed creation of a starkit, instead using the sdx.kit as a tool. The purpose is to do it in a more portable way than using exec. Many thanx in advance!

LV tb, I don't know whether I've seen any articles discussing how to create a starkit from tcl. HOWEVER, I do know you can do an sdx unwrap of sdx, which then gives you the source code for what sdx does. That should get you started. I would then suggest you pop over to http://groups.google.com/group/starkit , where the starkit people hang out. You can ask for explanations there - then perhaps return here and create a new page explaining the process to us!

tb - Ehem, I allready checked the code but found it relatively far from being reusable. All parameter-I/O is done using the argv environment instead of using the tcl/tk return stack. Functionalities where organized into files, that's ok, but they act more like a tool chain than being reusable modules. That's why I was asking here. I have started decomposing app-sdx to get the clue and tried to encapsulate wrap.tcl into a procedure, but I must be missing something. Maybe, I haven't found all exit's yet.


Questions which have been answered


Progress Indication

AdrianP 2007 July 25

I'm writing a UNIX-only terminal script that, in the course of its actions, needs to run a very long C application using "exec." (It is the BSD memtest actually). This works fine, but it lasts about 5 minutes and during that time the screen just freezes with the message "Running BSD memtest..." (since I redirect the output). Is there any easy way to have it print out a "." every 10 seconds or so while the memtest is running, just to assure the user that the program has not frozen, it's just taking a long time to execute? Nothing fancy, just an occasional "..."

Thanks in advance :)

CJL - With tweaks to suit your application, this seems to do the job:

  proc readable { chan } {
      if { [gets $chan bbuffer] < 0 } {
          fileevent $chan readable {}
          catch {close $chan}
          set ::done 1
      } else {
          puts $buffer
      }
  }

  proc tick { {interval 1000} } {
      puts -nonewline "."
      flush stdout
      set ::after_tick [after $interval [list tick $interval]]
  }

  set done 0

  set H [open "|/bin/sleep 10" "r"]
  fileevent $H readable [list readable $H]

  tick

  while { !$done } {
      vwait done
  }
  after cancel $after_tick
  puts "memtest complete"

AdrianP: Success! I had to massage the code quite a lot to fit into the [itcl\] app, but I got it. Thank you, CJL!

CJL - Glad it helped. I would have put some explanation in, and a link to the page for open if I'd been in less of a hurry (real work was demanding attention). But quite a lot of changes? I was expecting all you'd have to do was put the path to memtest in instead of '/bin/sleep'. But then I've never used itcl so I don't know what's involved there.


Ignoring the Main Window

LV 2007 July 05

A developer stopped by and was asking me a question. What I noticed, though, was that in his program design, he initially invokes some code (copied from the wiki, but the same would be true if he were using something from tklib, etc.) which creates a top level "login" type megawidget.

What he gets, as a result, is his login widget, but _on top of that_ the empty frame for "." which, at the point he is in his program, hasn't been packed yet.

Is there a standard method people use whereby "." is hidden until widgets have been packaged/gridded/placed into it?

MG I think the standard thing is to just [wm withdraw .] at the start of the app, then [wm deiconify .] when it's been packed and is ready to be used, whenever that may be (in this case, probably when the login details have been confirmed as valid).


Changing Directory

Dereckson: Good evening,

Each time I want develop a unix script in TCL, I'll finish with sh/tcl combinaison instead.

Is there a solution to allow a tclsh script to change the current directory?

I wish to chdir in a script but as the script is executed in its own interpretor, it doesn't influence shell.

My goal is a jump script, allowing to write "jump CI" instead "cd /home/wwwroot/domain.com/www/_includes/CodeIgniter/"

 #!/usr/bin/tclsh8.4

 #Reads the jump array
 source /etc/jump

 ...

 if {$argv == ""} {
        foreach "key value" [array get jump] {
                puts "[CompleteString $key 12] | $value"
        }
 } elseif [info exists jump($argv)] {
        #TODO : handle this in TCL to influence our calling shell :/
        cd $jump
 } else {
        puts stderr "Unknown destination: $argv"
 }

MG imagines this would just involve using exec to run the shell's cd command, instead of Tcl's cd command.

  exec cd $jump($argv)

If you're planning to do more things relative to that path in your Tcl script, you might also want to then use Tcl's cd command to change the Tcl interp into that directory, so you can open files there, etc, easily.

DcK Problem is cd isn't a real command but a shell built-in one. So, exec cd gives couldn't execute "cd": no such file or directory

MG Have you tried 'exec sh cd ...'? No idea if that'll work correctly, but it's the only other thing I can think to suggest (not really familiar with unix systems).

DcK sh has the same problem than tclsh when something is passed as arg, it treats it as command.

EMJ It is not possible for any script (or program) in any language to change the current directory for the shell it was called from, because it will always be running in a separate process. You will need to do something with shell aliases and/or shell functions, such as

 jump() {
    cd $(tcljump $1)
 }

where tcljump doesn't do a cd, but prints the resultant full path on it's stdout. Or maybe have a look at the CDPATH shell variable.

Duoas It is possible only if you use a little magic when running your script. For sh, run a subshell as:

 . ./myscript

All chdir commands in "myscript" will remain in effect when it terminates, since a new process was not created. You can use the alias command to make things more convenient.

Hope this helps.


Passing Procedures to Procedures

2007-05-23

AdrianP: Hello; I'm very new to Tcl (only a few days old), but I have a quick question about some syntax. Essentially I am trying to pass procs as parameters to other procs. For example, I'd like to be able to do something like this:

 proc a {} { return 5 }
 proc b { h } { puts "Hi" ; puts [$h] ; puts "Bye" }
 b $a

And have that print off:

 Hi
 5
 Bye

Of course, that doesn't work at all, since "$a" is not a variable and so can't be passed to b. I considered something like this:

 set a { return 5 }
 proc b { h } { puts "Hi" ; puts -"[eval $h]" ; puts "Bye" }
 b $a

But that only outputs

 Hi
 5

and stops execution there because "[eval $h]" creates a "return" which ends the parent procedure prematurely which is not what I wanted. I know I could do

 set a { set rc 5 }

and this will work for such a trivial procedure, but I may want much more complicated versions of 'a' that use 'return' for simplicity. I feel there MUST be a way to do this. I hope I made myself really clear, and I'm sorry for any ambiguity/silly questions. I am a brand new Tcler.

Thanks in advance all those who help! :)

MG In Tcl, using square brackets forces a string to be evaluated as a command (and its result is used in place of the square-bracketed string). So all you need to do is

 proc a {} { return 5 }
 proc b { h } { puts "Hi" ; puts "$h" ; puts "Bye" }
 b [a]

(proc "a" returns "5". proc "b" takes one arg ($h), and prints out "Hi", the value of the variable $h, and then "Bye". So in

 b [a]

it runs "a", substitutes it's result, and then runs "b" as

 b 5

giving you the desired result:

 Hi
 5
 Bye

Hope that helps some :)

AdrianP: MG, thank you for the quick response :) Unfortunately, in my attempt to simplify my situation so as to not bog my question down with context, I seem to have *over*-simplified it.

Yes, your solution works with my simple test case. However, my "real" a-function is a lot more complex than "return 5" and will return different things at different times. Thus I need it to be dynamically evaluated each time b is called, not just once at the beginning.

Any solutions in this case?

Lars H: I think

 proc a {} { return 5 }
 proc b { h } { puts "Hi" ; puts [$h] ; puts "Bye" }
 b a

(same as your original code, except no $ for the a) will do what you want. This is actually a special case of two common ways to "pass a procedure to a command" in Tcl: passing a script (as do most control structures, e.g. if, while, for, after) and passing a command prefix (last argument of trace, -command option of lsort, -command option of scrollbar, etc.). The first is in your case

 proc a2 {base factor} { return [expr {$base+5*$factor}] }
 proc b1 { h } { puts "Hi" ; puts [eval $h] ; puts "Bye" }
 b1 {a2 34 3}

and the second is

 proc a2 {base factor} { return [expr {$base+5*$factor}] }
 proc b2 { h } { puts "Hi" ; puts [{*}$h 3] ; puts "Bye" }
 b2 {a2 34}

({*}$h is an 8.5-ism; the classical bulletproof way to code this [{*}$h 3] is

 proc b { h } { puts "Hi" ; puts [eval [linsert $h end 34]] ; puts "Bye" }

Duoas Hey there AdrianP. One of the long-standing mantras of Tcl is Everything is a string. To do what you want you need only consider when a thing is evaluated.

  proc a {} { return {Hello, world!} }
  proc b fn { puts "Message: [$fn]" }
  b a

works exactly as expected, since $fn is first substituted with a then the whole thing is evaluated. You can even get fancier and add arguments:

  proc square x { return [expr {$x * $x}] }
  proc map ls f {
    foreach x $ls {
      lappend result [$f $x]
      }
    return $result
    }
  map {1 2 3 4} square
  --> 1 4 9 16

Just remember, variable substitution only happens once per evaluation. Hope this helps.

Oh yeah, the {*}$f stuff is for use when you don't know what kind of command is passed in as f. So instead of just a function name as argument you can give several parts of a command:

  proc map ls f {
    foreach x $ls {
      lappend result [{*}$f $x]
      }
    return $result
    }
  map {one two three four} {string length}
  --> 3 3 5 4

Enjoy!


Zarutian is feeling humorous and asks for an dodo omelet. No, actually am I looking for a name for a package/system that provides suspendable and serializable picol interps that can only communicate asynchroniusly with the rest of the world via messages sent to addresses that the picol already has in its addressbook. (Concepts: Capability based security and Actor concurrency) Any and all suggestions will be greatly appreciated, please. And of course if I am unclear let me know.

Zarutian 2007-05-18 21:25 (UTC): suchenwi proposed/offered the name Capas on the chat in the recent week. Any other suggestions? And as always please let me know if I need to clarify further.


Shipping ints over sockets

slg I'm trying to find out how to transfer 4-byte ints on a Tcl socket. When I transfer a numeric value like 1, it shows up with its char value of 31 on the receiving app. Incidently, the receiving app is not Tcl, but is a c program. Thanks, Steven in Dallas

LV Hi Steven. integer numeric values in c and tcl programs are typically stored as 2/4/8 bytes. And within those bytes, depending on the hardware, one may find that information is stored within those bytes in at least two different ways. One common was is called "little endian" format and the other is called "big endian" format.

The basic idea is whether one is going to see the four bytes as:

 00 00 00 01

or

 01 00 00 00

I'm uncertain where the "31" you are seeing is coming from. However, what you are going to need to find out is what order the bits of numbers need to be in for your C receiving application. Then you can make use of appropriate tcl functions for putting bits together in a particular order.

Zarutian 2007-05-18 21:35 (UTC): slg, so you want to send binary over socket connection? Well, first set encoding and newline translation to binary:

 fconfigure $sock -encoding binary -translation binary

then you need to translate the number to binary else you are going to send the number as ASCII text. Therefor:

 puts -nonewline $sock [binary format I $number]
 flush $sock

need more explaining? Dont hessitate to ask.

slg That's the answer I needed Zarutian - thanks.


Logic Circuits

Maria. "Top posting" [http://en.wikipedia.org/wiki/Top-posting] is considered bad netiquette. I've moved your comments below (and answered more of your questions).

Hi,

I'm new to coding in Tcl. I've used Tcl scripts but so far never had to write/modify one. From what I've seen, I really find it useful, and want to learn more. I need to test a simple logic circuit (let's say 2 gates and one mux controlling the output from one or the other gate), and would like to use Tcl for this. Sadly have no clue where to start. Anyone has a template/advice/guidelines I could use please?

The idea is to input all combinations of logic and check the output is what is expected.

Would be grateful for your help!

Many thanks.

Cheers

Maria

Duoas Hi Maria and welcome. Take a look at TkGate. If you want to do your own coding, you'll have to spend a little time Getting Started. A wonderful resource is also http://www.tcl.tk/man/tcl8.5/ .

For some high-level do-it-yourself abstractions, try something like:

  proc and args {   # (takes any number of boolean arguments)
    foreach arg $args {
      if {!$arg} {return false}
      }
    return true
    }

  proc or args {
    foreach arg $args {
      if {$arg} {return true}
      }
    return false
    }

  proc not arg {
    if {$arg} {return false} \
    else {return true}
    }

  proc nand args {
    return [not [eval and $args]]  ;# works with pre-8.5 versions of Tcl
    }

  proc nor args {
    return [not [eval or $args]]
    }

You can play with your gates easily. Say you want to do this:

         ___
  A-----\   \      D
         |   >o---+     ___
  B--+--/___/      \---\   \
     |   ___            |   >---Q
     +--|   \      /---/___/
        |    )----+
  C-----|___/      E

You can build a proc to do it easily:

  proc mux1 {a b c} {
    set d [nor $a $b]
    set e [and $b $c]
    set q [or $d $e]
    return $q
    }

Or all in one statement:

  proc mux1 {a b c} {
    return [or [nor $a $b] [and $b $c]]
    }

Hope this helps. -- RS adds how to run the thing, for example:

 foreach a {0 1} {
    foreach b {0 1} {
        foreach c {0 1} {
            puts "$a $b $c -> [mux1 $a $b $c]"
        }
    }
 }

Now running the script gives on stdout

 0 0 0 -> true
 0 0 1 -> true
 0 1 0 -> false
 0 1 1 -> true
 1 0 0 -> false
 1 0 1 -> false
 1 1 0 -> false
 1 1 1 -> true

Hi Duoas,

Thank you so much for the tips!! Today I managed to write a script (very rudimentary I believe you'd call it!) that tests one of the combinations (0,0) (and also checks the expected output is as should). Since it was my first attempt felt very proud of myself because it worked! :-) but then got frustrated afterwards because I thought "do I have to write a procedure like this for EVERY combination???" And also there are muxes I have to set one way, drive the first lot of combinations in, check o/p, then set the mux the other way and repeat....

Felt like an endless job (and infinite script)!!!

But what you showed below seems a great help.

I wish there was a GUI where you could enter all this info, press 'run' and out it comes a tcl script with all you want!!

(Have not tried it yet but is the TkGate you recommended something like this?). A quick look made it look interesting... will look closer.

Many thanks once again.

And keep this going. It's wonderful :-))

Cheers

Maria.

Duoas Yes, the frustrating thing about programming is that computers are really, really stupid. They don't know anything you (or someone, somewhere) hasn't told it. What computers are nice for is allowing us to think about really small things in really big ways.

This isn't too different from what you would have to do if you had a breadboard and a bunch of circuits and wires. You'd have to connect them all together. The same thing here with the computer. Every connection (or every different combination), sadly, requires its own procedure (that is, if you want the computer to remember the combination.

In real life, you turn the electricity on and the little circuit clock keeps sending out pulses that causes the combinations to continue updating themselves every fraction of a second. But as we are doing it here, it is like turning on the power, getting a result, then immediately turning the power back off.

For example, suppose you want to do a simple flip-flop.

  proc ff {q qq r s} {
    set q  [nand $r $qq]
    set qq [nand $s $q]
    return [list $q $qq]
    }

A flip-flop is supposed to hold state: it 'rememebers' whether q is 0 or 1. However, the way we're turning the power on and off there is no way for it to remember the value of q and qq (q-prime) every time you call it.

  % puts [ff 1 0 1 0]
  1 1

This demonstrates the other problem: one pass through this proc doesn't give the flip-flop time to equalize itself. We get "1 1" back out because it is only half fixed. If we continue:

  % puts [ff 1 1 1 0]
  0 1

then we get the right answer. This is a very simple circuit. In real-life, these changes occur so fast we don't consider them distinct events. But programming it like we do exposes the truth.

One way to address the problem is to put things into loops like RS suggests above. Only for this circuit, you'll need one more loop in the center to give the flip-flop time to decide its state. Something like:

  set q  0
  set qq 1
  foreach a {0 1} {
     foreach b {0 1} {

       # allow our flip flop to settle using a loop
       foreach n {- - - - -} {  # (all 'n' does is cause us to loop as many times as there are dashes)
         lassign [ff $q $qq $a $b] q qq
         }

       # display the result
       puts "$a $b -> $q $qq"
     }
  }

Oh yeah, and the output:

  0 0 -> 1 1  (correct, the flip-flop is in an illegal state)
  0 1 -> 1 0  (correct, q is set to 1)
  1 0 -> 0 1  (correct, q is set to 0)
  1 1 -> 0 1  (correct, q remembers that it is currently 0)

I don't know if TkGate can produce scripts you can play with, but it will simulate active circuits.

Hope this helps.


  [gold] 8May2007. a. solved 11May & gracefully bow out.

Advanced Scrolling

I'd like to have page-up/page-down keys scroll in various different widgets in one large window. But don't want to give these widgets focus, so they aren't able to get keyboard events. Alternatively I could make my bindings to "." and multiplex out to the right widget -- if there were an easy way to detect which widget the mouse is over when a keyboard event is received. Is there? Thanks.

Duoas There's no direct way. What you'll have to do is track which widget has focus and send the key event appropriately. Something like:

 bind updn <Enter> {if {{updn} in [bindtags %W]} {set ::active_widget %W} {set ::active_widget {}}}
 bind updn <Prior> {catch {$::active_widget yview scroll -1 pages}}
 bind updn <Next>  {catch {$::active_widget yview scroll  1 pages}}

 bindtags . [concat updn [bindtags .]]

Here, the root widget tracks which "scrollable" widget (widgets with the "updn" bindtag) has focus, if any. When a PageUp/PageDown keypress is received, it is dispactched as a scroll command to the currently active scrollable widget, if any.

Hope this helps.

MG I think you can use something along the lines of

 winfo containing -displayof . [winfo pointerx .] [winfo pointery .]

to find out which window (if any) the pointer is in at the moment. Something along the lines of (half of this stolen from Duoas' example):

  set toplevel .
  bind $toplevel <Prior> "scroll $toplevel -1"
  bind $toplevel <Next> "scroll $toplevel 1"
  proc scroll {toplevel num} {
   set w [winfo containing -displayof $toplevel [winfo pointerx $toplevel] [winfo pointery $toplevel]]
   if { $w == "" } {
        return;
      }
   catch {$w yview scroll $num pages}
  }

Duoas Very nice. That's actually a superior solution, as it avoids the use of a global variable. The only gotcha is that you might try scrolling a window which doesn't explicitly want it (a condition I mindlessly added to the original proposition).

ABR Thanks, "winfo containing" was what I was looking for. For some reason I thought it would just give me the top-level "window" (.) but in fact it gives actual widget -- fantastic!


Bracketing

2007-06027 GWM Why does bracketing this not work:

  set sign -
  set valu 1.234
  expr {$sign$valu}

See Brace your expr-essions for answers to GWM's question. I have left this short response as it does not (in my opinion) improve the answer given, although it is useful information.

MG While Tcl does let you have variables for the values (numbers) inside a braced expression, it doesn't let you include the operator in a variable. I don't know /why/ that is, but that's why some of your examples work and some don't. If you need to have the operator in a variable, you can't brace the expression - I suspect it may be quicker to use something like

  set num1 5
  set num2 10
  set foo +
  # this
  if { $foo == "+" } {
       expr {$num1+$num2}
     } else {
       expr {$num1-$num2}
     }
  # rather than
  expr $num1$foo$num2

particularly if you're doing a lot of calls to expr, or more complex calculations than my example. (Would be interested to hear the reasons why Tcl doesn't allow it, though - all I've ever read before is that it doesn't.)

TJE A shorter solution closer in spirit to the request... Use 'subst' to do the variable expansion in a more extensible manner:

  set op +
  set num1 5
  set num2 10
  expr [subst {$num1 $op $num2}]

(Lars - your additional comment was moved to the brace your expressions page where the entire question and its responses are listed now that we have the answer). The move was because Ask, and it shall be given. says "In order to leave room for unanswered questions, please move your question to the appropriate page on Wikit once it has been answered. If you cannot find a page, please create a new one". That is why I "deleted" it - because that is the meaning of "to move". I didn't move the other parts of the answers as they were effectively better answered by your response which was moved. There is a clear pointer to where your response can be found above.

LV To whom ever wrote that last comment - thanks for explaining. I didn't understand your comment earlier, so I didn't understand that you had moved some of the info. Thanks though - that is useful to do. Another thing that I probably should put over there on that earlier page is that once a question has been answered, it is useful to move it down the page a bit, or move the remaining unanswered questions up (whatever), so the remaining question are profiled.

GWM Sorry for any inconvenience/upset.


Serial Device Emulator

BobC Serial device emulator in TCL/Tk?

I have a small embedded sensor running on a PIC that talks to a larger embedded device using an extremely simple serial protocol. The small device reports its readings via RS-232 at 30 Hz, but will also listen to a few commands (to get/set a handful of configuration parameters) and insert replies into the output stream.

I suspect TCL/Tk may be a good implementation platform for this, since I also need a GUI to view/modify internal states (e.g., to emulate failures). But I'm clueless about the TCL architecture needed to tie multiple things together: Gui, 30 Hz timer, serial port I/O.

The initial implementation needs to run on Windows, which means this would be a snap to implement in VB. However, I'd like to be cross-platform if possible, since we are slowly evaluating moving all developers to Linux.

My own TCL/Tk experience has been limited to using Expect to monitor/test other RS-232 protocols (I'm primarily an embedded C guy). Is TCL/Tk an appropriate choice for this emulator? If so, then I suspect something like this has been done before: Unfortunately, I've been unable to Google my way to enlightenment. Any suggestions?

TIA,

-BobC

AM (12 september 2007) I am utterly unfamiliar with such devices (even though I may be using a plethora of them in everyday life ;) - numerical computations and graphical presentations are the subjects I am more comfortable with) but have you searched for "serial" or even "serial*" on the Wiki? There are plenty of pages that seem at least tangential to your question.

BobC (12 Sep 2007) I'll try to break it down:

  1. Send messages at 30 Hz.
  2. Run an algorithm to generate 30 Hz messages, per GUI settings.
  3. Listen for asynchronous commands.
  4. Reply to asynchronous commands, per GUI settings.
  5. Interact with the user to inspect and modify state data.

In a conventional compiled language environment, I'd have an output queue emptied by a message transmitter thread that runs preemptively at 30 Hz. I'd have another thread reading the input port as needed (ideally sleeping on an Rx interrupt), build the reply, then put the reply message in the output queue. A third thread would run the GUI, and manage parametric actions (generate 30 Hz messages) by monitoring a 30 Hz timer.

I'm not sure how best to do stuff like this in TCL. The examples I've found illustrating the individual concepts don't give me ideas for how to combine them. I'm not yet good enough at TCL/Tk to look at more complex apps and extract what I need.

Perhaps this is a bit much to do for my first "serious" TCL/Tk app, though I had hoped it would be relatively straightforward to do.

AM (13 september 2007) Well, a part of the decription above I can understand (I am a software guy, keep that in mind :)):

 proc sendMessage {chan msg} {
     puts $chan $msg
     after [expr {1000/30}] [list sendMessage $chan $msg]
 }

 sendMessage stdout "Hello"
 vwait forever

The above script will write a text to the channel of your choice (in this case: standard output) and repeat that after 33 ms (the after command takes a delay in milliseconds). Mind you: that is only an approximate time. If you need a more accurate timing, you would probably need to do something like

  • Check the time each ms (with an after script like the above)
  • If 33 ms have passed, send a message
  • Set the new reference time

Now getting the input from a channel that is not a file on disk is probably easiest using the [fileevent] command.

There are plenty of examples on the Wiki on how to do that, for instance, Managing Fortran Programs.

Lars H: Does the 30 Hz refer to the number of message per second (as AM seems to assume) or the baud rate (bitrate counting also start, stop, and partity bits)? The latter sounds more probable to me, even though 30Hz feels rather slow.

You may be looking for a too-low-level interface to this if you expect your program to generate the individual bits. The manpage of open has a long section of options for serial port channels, e.g. there is -mode which lets you set "baud rate, parity, number of data bits, and number of stop bits". Then just write your characters to the channel and have the system take care of delivering them.

escargo 13 Sep 2007 - I think the original question was actually precise enough. 30 Hz might be an appropriate rate for a "keep-alive" kind of message. A watch-dog timer at the other end might allow for a couple of missing messages before assuming the sender's device has died. (This reminds me of rate-structured executives more common in military applications.) The after loop and waiting on fileevent would seem to be the key concepts in implementation.

BobC Yes, there are 30 "data" messages sent per second, with "reply" messages inserted as needed (and are permittited to replace "data" messages). The parameters controlling everything are in the GUI thread (generated via GUIbuilder).

I noticed the "after" statement, which seems to be only useful as an in-line delay, and not as a true timer. To get "real" 30 Hz performance, I assume I'll need a 33 ms synchronous timer accessed as an event of some kind. Would it be better to do the precise timing and serial I/O as a separate C program? Or can TCL create and respond to such an event?

Alternatively, if I could somehow slave the GUI updates to a 30 Hz rate (let's assume my CPU has infinite speed), would I then be able to do everything within the GUI thread?

escargo 17 Sep 2007 - (Do observe the top of the page, where it says that new questions should go to the top, not to the bottom. However, since I just want to answer the question, not complain, I'll continue replying down here.) I would certainly leave the keep-alive separate from the GUI. You might clarify how much jitter your 30 Hz messages are allowed. You also don't mention how much control you have over the expectations at the receiving end. This could be anything between complete control to no control, with a hard 30.000 Hz frequency required. One thing you could try fairly easily to see if the after loop was close enough, and then determine whether you needed anything more complex to meet your requirement.

Lars H, 20 Sep 2007: It should be observed that although after without a script pauses the interpreter for a particular duration, the main form of that command is the one with a script. In that case, it starts a timer which when it fires places the script in the event queue for processing. Thus the effect of

  after 33 $script

is typically that the $script is evaluated 33ms later, possibly slightly later if a different event is being serviced at that time. after events with specified time are serviced before GUI update events. If you consider 1/30Hz = 33ms ("jitter" of the magnitude 1/3 ms is not even noticable) then this should be good enough for you.

BobC, Bottom-posting yet again on 20 Sep 2007: So, what I want to do should look something like this:

  proc do33ms {args} {
    # Immediately schedule the next run
    after 33 do33ms
    # Prepare packet...
    # Send packet...
  }

In my init routine, I'd do an initial call to do33ms, and it would take care of itself after that, right? Assuming, of course, do33ms takes less than 33ms to run. Do I need to worry about reentrancy for serial port writes? (Use unbuffered output?)

escargo - My understanding is that reentrancy is not an issue; the Tcl interpreter is going through an event loop and processing one thing at a time. There might be more than one thing ready to do, but only one runs at a time. It wouldn't be a bad idea to make the after command conditional on a global variable that tells it not to reschedule itself. (Preparing for an orderly shutdown, for example.) You could even check the time to a finer degree and make the after a little bigger or smaller depending on how close you are to your expected schedule.



Please add questions at the top of this page.