Why another parsing-routine? Because the other ones like cmdline or OptProc are a little overweighted or just too complex. Here in the wiki, I found links to various usefull parsing-routines, but still I decieded to write one of my own; here is the result. The input is checked/processed against a template, and the result is given back as a list suitable for array set. Switchnames may be shortened. At the bottom of the page later I will add some examples of how a commandline and the corresponding templates can look like.


 # Simple ParameterParsing (SPar)
 # 08.03.2005

 proc spar {tpl cmd} {
      if {[catch {array set a $tpl}]} {
         return -code error {invalid template}; # we could'nt handle this error
      }; # don't stop with other errors - give pgmr the chance to decide later
      set needmore {}
      set count    0
      set seeopts  1
      foreach item $cmd {
              if {[string equal $item "--"]} {
                 set seeopts 0; # end of -flag-processing
              } elseif {[string length $needmore]} {
                 set a($needmore) $item
                 set needmore {}
              } elseif {$seeopts == 1 && [string range $item 0 0] == "-"} {
                 set matches [array names a -glob $item*]; # allows shortening
                 if {[llength $matches]} {
                    set match [lindex [lsort $matches] 0]
                    if {[string index $match end] == ":"} {
                       set needmore $match; # -f: means: 'value follows'
                    } else {
                       set a($match) 1; # otherwise simply return 'true'
                    }
                 } else {
                    lappend a(swiunknown) $item
                 }
              } else {
                 incr count; # each arg counts, even if there are too much
                 if {[info exists a($count)]} {
                    set a($count) $item
                    set a(argcount) $count
                 } else {
                    lappend a(argsuper) $item
                 }
              }
      }
      if {[string length $needmore]} {
         set a(swinovalue) $needmore; # missing value after -switch: at the very end
      }
      return [array get a]; # double conversion is the price for using arrays
 }

 # Tests
 set tpl [list -f1 0 -f2 0 -f3: "*" -f4 0 -test 0 1 "" 2 "" 3 "Default3" -? 0]
 puts "Template: $tpl\n"
 puts Commandline:
 gets stdin cmd
 if {![catch {array set a [spar $tpl $cmd]} rc]} {
    puts "Resultarray:\n"
    parray a
 } else {
    puts $rc
 }

(Examples will be added later)


Command Line Parsing, enhanced (but yet simple) version with integrated help support

(German Version)

 # Simple ParameterParsing (SPar) SPAR_NEW6.TCL
 # (C) M.Hoffmann 2004-2005
 #
 # 26.03.2005: Erweiterung: Hilfetexte mit übergeben, formatierte Hilfeausgabe
 # 05.07.2005: ReView, Ergänzungen
 # 09.07.2005: endgültige Hilfeformatierung festgelegt
 # 11.07.2005: Leere pos. Args überschreiben nicht Default; Hilfe integriert;
 #             package
 #
 # ToDo:
 #  - Doku (hier)
 #  - namespace
 #  - Testcase, Demos
 #  - Wiki
 #
 # Unterstützte Sonderzeichen in Hilfezeilen:
 #  %s - ergibt den Switchnamen selbst (bei Pos.args nicht sinnvoll!)
 #  %v - ergibt [Vorgabewert]
 #  %n - Spaltengerechter manueller Zeilenumbruch

 package provide Spar 1.0

 proc spar {tpl cmd} {
      if {[catch {array set a $tpl}]} {
         return -code error {invalid template}; # we could'nt handle this error
      }; # don't stop with other errors - give pgmr the chance to decide later
      # Help extension, formerly in separate proc
      set col 0
      set sntx {}
      set help {}
      foreach name [lsort [array names a]] {
              set lCol     [lindex $a($name) 1]; # left side of help
              set rCol [lrange $a($name) 2 end]; # right side of help
              set a($name) [lindex $a($name) 0]; # the value ifself
              set lCol [string map "%s $name" $lCol]; # 'switch' replaces %s
              if {[string length $lCol]} {
                 append sntx "$lCol "
                 append help "\[format %-\${col}s $lCol\]$rCol\n"
                 set l   [string length $lCol]         ; # determine begin of
                 set col [expr {$l > $col ? $l : $col}]; # right side of help
              }
      }
      incr col
      set nl "\n[string repeat " " $col]"
      set a(help) "$sntx\n\n[string map [list %v \[$a($name)\] %n $nl] [subst $help]]"
      # Help extension End
      set needmore {}
      set count    0
      set seeopts  1
      foreach item $cmd {
              if {[string equal $item "--"]} {
                 set seeopts 0; # end of -flag-processing
              } elseif {[string length $needmore]} {
                 set a($needmore) $item
                 set needmore {}
              } elseif {$seeopts == 1 && [string range $item 0 0] == "-"} {
                 set matches [array names a -glob $item*]; # allows shortening
                 if {[llength $matches]} {
                    set match [lindex [lsort $matches] 0]
                    if {[string index $match end] == ":"} {
                       set needmore $match; # -f: means: 'value follows'
                    } else {
                       set a($match) 1; # otherwise simply return 'true'
                    }
                 } else {
                    lappend a(swiunknown) $item
                 }
              } else {
                 incr count; # each arg counts, even if there are too much
                 if {[info exists a($count)]} {
                    if {[string length $item]} {
                       # Defaults can only be overridden by 'real' values
                       set a($count) $item; # empty string causes skip
                    }
                    set a(argcount) $count
                 } else {
                    lappend a(argsuper) $item
                 }
              }
      }
      if {[string length $needmore]} {
         set a(swinovalue) $needmore; # missing value after -switch: at very end
      }
      return [array get a]; # double conversion is the price for using arrays...
 }

Testroutine (like documentation, is still a work in progress...)

# Tests for Simple Parameter parsing (Spar) module

 # 11.07.2005

 lappend auto_path ./
 package require Spar 1.0

 # Template Format
 #
 # The template must be a proper list suitable for `array set`!
 #
 # basic format (without help) {
 #   -flagname|-optionname:|{1|2|...} default_value
 #   -flagname|-optionname:|{1|2|...} default_value
 #           :                            :
 # }
 #
 # where:
 #  '-flagname' is - well - a flag: the presence of it always returns
 #  1 (true), so the default value should almost always be 0 (false);
 #  '-optionname:' denotes a named arg, again initializied with a
 #  default value;
 #  1,2,...n is a placeholder for a positional argument. it's also
 #  possible to specify a default value for missing positional args.
 #
 # extended format (with help) {
 #   -flagname|-optionname:|{1|2|...} {default_value helptext ...}
 #   -flagname|-optionname:|{1|2|...} {default_value helptext ...}
 #           :                            :
 # }
 #
 # helptext may contain %s (replaced by flag/optionname), %v
 # (replaced by defaultvalue, surrounded with brackets) or %n
 # (newline)

 # Setup Array With Example Template

 set tpl {-flag1 {0          %s  A boolean flag. if present, 1 will be returned}
          -f2    {""         %s               Ein Boolflag, bei Auftreten wird 1 geliefert. Dieser Hilfetext ist%nsehr lang, er wird manuell umgebrochen.}
-f3
{"flag3def" %s<wert> Ein benanntes Argument (Key-value-Paar) %v}
          -f4    {0  %s               Noch ein Boolflag...}
          -test  0
          1      ""
          2      Vorgabe2
          3     {Default3 <feld3x>   Ein Feld an Pos3 %v}
          -?     0
 }
 puts "Template: $tpl\n"
 puts Commandline:
 gets stdin cmd
 if {![catch {array set a [spar $tpl $cmd]} rc]} {
    puts "Resultarray:\n"
    parray a
 } else {
    puts $rc
 }
 puts \n*****************\n
 puts $a(help) 

oops! Something's wrong above with wiki formatting.... no time now to fix it...


Category Argument Processing