When I wrote text base programs in high-level programming languages, I often need to create a simple menu, get the user’s choice, then dispatch the appropriate procedure. The dispatch code often include lengthy swich (case) statement:
switch (choice) {
case 'a':
function_a();
break;
case 'b':
function_b();
break;
}
...
This design pattern was fine if the menu is relatively short. As the menu grows, adding a choice to the menu means: 1) Add lines to the menu, 2) update the switch statement, and 3) write another function to handle the new choice.
This design pattern bears several problems:
- Adding an additional choice to the menu requires a lot of works as illustrated
- Programmer must take care to keep the menu and the switch statement in sync.
- As the menu grows, the switch statement can get very long
Fortunately, Tcl offers an easy remedy to this problem: commandloop. I wrote about commandloop before as my way to setup a break point for debugging purpose. Commandloop can do more than that. In this case, I can commandloop to provide dispatch to my procedures. Consider the following simple script:
package require Tclx
set stack {}
proc stack {} { set ::stack }
proc push {item} { lappend ::stack $item }
proc pop {} {
set item [lindex $::stack end]
set ::stack [lreplace $::stack end end]
return $item
}
commandloop
This script simulates a stack; it provides three commands (procedures): stack to display the contents of the stack and the self-explanatory push and pop. The script’s main body consists of a single commandloop command. So how does this works?
The commandloop command allow the users to interact with the script, including the ability to call the script’s commands. Let’s take a look at an interactive session:
$ ./commandloop1.tcl
%stack
%push 5
5
%push 7
5 7
%push -3
5 7 -3
%stack
5 7 -3
%pop
-3
%stack
5 7
%set x 0
%push $x
5 7 0
%puts "Stack contents: [stack]"
Stack contents: 5 7 0
%exit
$
After launching the script, we arrive at the ‘%’ prompt. From there, we can issue the script’s commands such as stack, push, and pop. Not only that, we can also set additional variables (such as x). We can all issue other commands such as puts. In short, the commandloop command opens up an interpreter to interact with the script. Finally, the exit command (or Ctrl-D in Linux, Ctrl-Z in Windows) exits the command loop and ends the script.
Commandloop comes with some handy optional flags. The first is the -endcommand flag. This flag specifies a command (or procedure) to execute after commandloop terminates. Note that after commandloop terminates, the script’s execution will stop, ignoring any command that follows. If you want to execute a command after the commandloop terminates, use this flag.
Another flag of interest is the -prompt1 flag. This flag allows the users to customize the prompt if they don’t like the default one. These are the two flags I use most often. For information regarding other flags, you can look up information for commandloop in the Tclx package.
