'''Tcl Template Parser''' - http://www.magma.com.ni/sw/ttp/ Started from the need to create lots of files from a templates and some variable definitions. Now it is several things: * Still a versatile template parser * A compact (254 sloc) wrapper for Tcl applications, with commandline and configuration file parser. * An example of a real live programm written with [Compact Code Formatting Style] Look at the (hopefully soon) comprehensive documentation if you want to use the programm. On this page I want to present some concepts used when coding TTP. ---- '''Commandline parsing with active tokens and recursion''' The initial commandline parser i used was a simple while loop, it makes use of the "shift" proc which pops off an element of a list. set params {} set cl $argv while {[llength $cl]} { set t [pop cl] switch -- $t { -h {usage; exit 0} -d {set ::loglevel [pop cl]} ... default {lappend params $t}}} This is a very simple minded parser which requires all options and parameters to be separated by whitespace, consumes all arguments of the commandline, and pushes everything that is not defined as option - arguments, hopefully - on a list for later usage. 'pop' is made in a way, that it always pops off an empty list from an empty list. Since 'while is bad' i wanted to do better and recurred to the intrinsic list processing feature of 'proc': * every option is defined as a proc, consuming exactly the arguments it needs * argv is processed recursively, there will not be thousands of switches on my commandlines Here comes the whole parser: proc options args {if [llength $args] {eval $args}} It is started with: eval options $argv Very self-describing, isn't it? It has no syntax though, so let's make one: proc -h args {usage; exit 0} proc -d loglevel {set ::loglevel $loglevel; eval options $args} ... If we 'eval options -d 4 -h' the following will happen: * '-d' is called with parameters '4 -h', which sets ::loglevel to 4 and calls 'eval options -h' * '-h' is called, which prints out the 'usage' message and goes home But how about parameters? They would be 'eval'ed and trigger an error: invalid command name "..."\nwhile evaluating '...'. This is the default behaviour of the [unknown] function and not what we want, so let's redefine it. 'unknown' is called with the (unknown) commandname and the (variable) argumentlist. The commandname is our parameter from the commandline: proc unknown {param args} { lappend params $param; eval options $args} So Tcl handles lets put it together: set params {} proc -h args {usage; exit 0} proc -d {loglevel args} {set ::loglevel $loglevel; eval options $args} # more options here ... proc options args {if [llength $args] {eval $args}} proc unknown {param args} { lappend ::params $param; eval options $args} eval options $argv While this is not really shorter than the while loop, it has some errorhandling built in, e.g. if you specify '-d' without a following argument, Tcl personally rants: 'wrong # args: should be "-d loglevel args"' If you specify 'set ::loglevel 8' on the commandline, you get it set to 8, because the 'parameter' set is not unknown. So if you want to avoid Tcl code 'injection' from the commandline you better run the parser inside a slave interpreter with only the -option commands. The commandline parser in TTP is much more elaborate, to account for some of such pitfalls. It also makes use of code introspection to generate the 'usage' message automatically. How this? In the two above examples of -option procedures you see that the argument list (minus 'args') shows as directly the number (and connotation) of the arguments of a commandline option. We can get a list of options with 'info procs -*' and the argument list of a specific option with e.g. 'info args -d'. Tcl does not supported procedure comments like e.g. in some lisp dialects, however you could cope with this by defining your options this way: proc -h args {# give usage message usage; exit 0} Then you can get to the option comment with 'lindex [[split [[info body -h]] 0]]'; of course you need to strip off the '# ' in front of the comment. From all this you can create lines like: -h .. give usage message -d loglevel .. set loglevlel automatically. If you add an option, you automatically get it added to the usage message. [LEG]