############################################################################### # BRLTTY - A background process providing access to the console screen (when in # text mode) for a blind person using a refreshable braille display. # # Copyright (C) 1995-2018 by The BRLTTY Developers. # # BRLTTY comes with ABSOLUTELY NO WARRANTY. # # This is free software, placed under the terms of the # GNU Lesser General Public License, as published by the Free Software # Foundation; either version 2.1 of the License, or (at your option) any # later version. Please see the file LICENSE-LGPL for details. # # Web Page: http://brltty.com/ # # This software is maintained by Dave Mielke . ############################################################################### set sourceDirectory [file normalize [file dirname [info script]]] if {[catch [list package require Tclx] response] != 0} { proc lvarcat {list elements} { uplevel 1 [list lappend $list] $elements } proc intersect3 {list1 list2} { foreach number {1 2} { set length$number [llength [set list$number [lsort [set list$number]]]] set index$number 0 set only$number [list] } set both [list] while {1} { if {$index1 == $length1} { if {$index2 < $length2} { lvarcat only2 [lrange $list2 $index2 end] } break } if {$index2 == $length2} { lvarcat only1 [lrange $list1 $index1 end] break } switch -exact -- [string compare [lindex $list1 $index1] [lindex $list2 $index2]] { -1 { lappend only1 [lindex $list1 $index1] incr index1 } 1 { lappend only2 [lindex $list2 $index2] incr index2 } 0 { lappend both [lindex $list1 $index1] incr index1 incr index2 } } } return [list $only1 $both $only2] } proc lrmdups {list} { return [lsort -unique $list] } proc lempty {list} { return [expr {[llength $list] == 0}] } if {[package vcompare $tcl_version 8.4] < 0} { proc readdir {directory} { set workingDirectory [pwd] cd $directory set names [glob -nocomplain *] cd $workingDirectory return $names } } else { proc readdir {directory} { return [glob -directory $directory -tails -nocomplain *] } } } proc makeEnumeration {arrayVariable elements} { upvar 1 $arrayVariable array set value 0 foreach element $elements { set array($element) $value incr value } } proc getProgramName {} { return [file tail [info script]] } proc writeProgramMessage {message} { set stream stderr puts $stream "[getProgramName]: $message" flush $stream } makeEnumeration logLevels { debug information notice warning error alert critical emergency } set logLevel $logLevels(notice) proc logMessage {level message} { global logLevels logLevel if {$logLevels($level) >= $logLevel} { writeProgramMessage $message } } proc syntaxError {{message ""}} { if {[string length $message] > 0} { writeProgramMessage $message } exit 2 } proc semanticError {{message ""}} { if {[string length $message] > 0} { writeProgramMessage $message } exit 3 } proc nextOperand {operandsVariable {operandVariable ""}} { upvar 1 $operandsVariable operands if {[llength $operands] == 0} { return 0 } if {[string length $operandVariable] > 0} { uplevel 1 [list set $operandVariable [lindex $operands 0]] set operands [lreplace $operands 0 0] } return 1 } proc processOptions {valuesArray argumentsVariable definitions} { upvar 1 $valuesArray values upvar 1 $argumentsVariable arguments set prefix - set options [dict create] set index 0 foreach definition $definitions { set description "option\[$index\]" if {![nextOperand definition name]} { return -code error "name not specified for $description" } if {[dict exists $options $name]} { return -code error "duplicate name for $description: $name" } if {![nextOperand definition type]} { return -code error "type not specified for $description" } if {[lsearch -exact {counter flag toggle} $type] >= 0} { set values($name) 0 } elseif {[lsearch -exact {untyped} $type] < 0} { if {[catch [list string is $type ""]] != 0} { return -code error "invalid type for $description: $type" } } dict set options $name type $type incr index } while {[llength $arguments] > 0} { if {[string length [set argument [lindex $arguments 0]]] == 0} { break } if {![string equal [string index $argument 0] $prefix]} { break } if {[string length [set name [string range $argument 1 end]]] == 0} { break } set arguments [lreplace $arguments 0 0] if {[string equal $name $prefix]} { break } if {[set count [dict size [set subset [dict filter $options key $name*]]]] == 0} { writeProgramMessage "unknown option: $prefix$name" return 0 } if {$count > 1} { writeProgramMessage "ambiguous option: $prefix$name" return 0 } set name [lindex [dict keys $subset] 0] set option [dict get $subset $name] switch -exact [set type [dict get $option type]] { counter { set value [expr {$values($name) + 1}] } flag { set value 1 } toggle { set value [expr {!$values($name)}] } default { if {[llength $arguments] == 0} { writeProgramMessage "missing operand: $prefix$name" return 0 } set value [lindex $arguments 0] set arguments [lreplace $arguments 0 0] if {![string equal $type untyped]} { if {[catch [list string is $type -strict $value] result] != 0} { return -code error "unimplemented option type: $type" } if {!$result} { writeProgramMessage "operand not $type: $prefix$name $value" return 0 } } } } set values($name) $value } return 1 }